【WPF】Prism学习(二)

Prism Commands

在这里插入图片描述

1.命令(Commanding)

1.1. ViewModel的作用

  • ViewModel不仅提供在视图中显示或编辑的数据,还可能定义一个或多个用户可以执行的动作或操作。
  • 这些用户可以通过用户界面(UI)执行的动作或操作通常被定义为命令(Commands)。

1.2. 命令(Commands)的作用

  • 命令提供了一种方便的方式来表示可以轻松绑定到UI控件的动作或操作。
  • 它们封装了实现动作或操作的实际代码,并有助于将其与视图中的实际视觉表示分离。

1.3. 命令的触发方式

  • 用户与视图交互时,可以通过多种方式视觉上表示和调用命令。
  • 大多数情况下,命令是由鼠标点击触发的,但它们也可以由快捷键按下、触摸手势或其他输入事件触发。
  • 视图中的控件与ViewModel的命令数据绑定,因此用户可以使用控件定义的任何输入事件或手势来调用它们。
  • 视图中的UI控件与命令之间的交互可以是双向的,即命令可以在用户与UI交互时被调用,UI也可以根据底层命令的启用或禁用状态自动启用或禁用。

1.4. 命令对象的实现

  • ViewModel可以将命令实现为命令对象(一个实现了ICommand接口的对象)。
  • 视图与命令的交互可以声明性地定义,而不需要在视图的代码后台文件中编写复杂的事件处理代码。
  • 例如,某些控件天生支持命令,并提供了一个可以与ViewModel提供的ICommand对象数据绑定的Command属性。
  • 在其他情况下,可以使用命令行为将控件与ViewModel提供的命令方法或命令对象关联起来。

1.5. ICommand接口的实现

  • 实现ICommand接口是直接的。
  • Prism框架提供了DelegateCommand这个ICommand接口的实现,你可以在你的应用程序中直接使用它。

DelegateCommand可以在Prism.Core Nuget包的Prism.Commands命名空间中找到。

2.创建一个委托命令对象

如何在MVVM模式中使用DelegateCommand来实现命令,以及如何将这些命令绑定到UI控件上。

2.1. DelegateCommand类封装了两个委托,这两个委托分别对应于ViewModel中的ExecuteCanExecute方法。这意味着,当你在UI中触发一个命令时,DelegateCommand会调用ViewModel中相应的方法。

2.2. 你可以通过DelegateCommand类的构造函数来指定这些委托。例如,下面的代码示例展示了如何通过指定委托到ViewModel中的SubmitCanSubmit方法来构造一个代表提交命令的DelegateCommand实例。然后,这个命令通过一个只读属性暴露给视图,该属性返回对DelegateCommand的引用。

public class ArticleViewModel
{public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand<object>(Submit, CanSubmit);}void Submit(object parameter){// 实现逻辑}bool CanSubmit(object parameter){return true;}
}

2.3. 当DelegateCommand对象的Execute方法被调用时,它会通过你在构造函数中指定的委托将调用转发到ViewModel类中的方法。同样,当CanExecute方法被调用时,会调用ViewModel类中的对应方法。CanExecute方法的委托在构造函数中是可选的。如果没有指定,DelegateCommand将始终返回true作为CanExecute的结果。

2.4. DelegateCommand类是一个泛型类型。类型参数指定了传递给ExecuteCanExecute方法的命令参数的类型。在上面的例子中,命令参数是object类型。Prism还提供了一个非泛型的DelegateCommand类,用于不需要命令参数的情况,定义如下:

public class ArticleViewModel
{public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand(Submit, CanSubmit);}void Submit(){// 实现逻辑}bool CanSubmit(){return true;}
}

DelegateCommand避免使用值类型作为参数,如果需要使用值类型参数时,应该如何处理以避免潜在的问题:

  1. DelegateCommand避免使用值类型DelegateCommand这个类在设计时故意不使用值类型(如intdoublebool等)作为参数类型。这是因为ICommand接口接受的是一个对象类型的参数。
  2. 值类型参数可能导致意外行为:如果在XAML初始化时,命令绑定调用了CanExecute(null),并且T是一个值类型,那么可能会导致一些意料之外的行为。这是因为值类型在默认情况下会被初始化为它们的默认值(如int的默认值是0),这可能会导致命令的执行逻辑出现问题。
  3. 默认值问题:考虑过使用default(T)作为解决方案,但最终被拒绝了。原因是实现者将无法区分一个有效的值和一个默认值。例如,如果Tint,那么default(int)是0,但实现者可能无法确定0是一个有效的参数值还是一个默认值。
  4. 使用可空类型:如果你确实需要使用值类型作为参数,那么必须将其转换为可空类型(nullable)。这可以通过使用DelegateCommand<Nullable<int>>或者使用简写形式?语法(DelegateCommand<int?>)来实现。这样,就可以区分一个有效的值和一个未赋值(null)的情况。

3.在视图中调用 ViewModel 提供的 DelegateCommands

3.1. 视图与命令对象的关联:在视图中,可以通过 Command 属性将控件与 ViewModel 提供的命令对象关联起来。这适用于 WPF、Xamarin.Forms 和 UWP 控件,它们可以通过数据绑定轻松地与命令对象关联。

3.2. 数据绑定示例:提供了一个按钮的示例代码,展示了如何将按钮的 Command 属性绑定到 ViewModel 中的 SubmitCommand 命令上。代码如下:

<Button Command="{Binding SubmitCommand}" CommandParameter="OrderId"/>

这里,{Binding SubmitCommand} 表示将按钮的 Command 属性绑定到 ViewModel 的 SubmitCommand 属性上,CommandParameter="OrderId" 表示传递一个参数 “OrderId” 给命令的 Execute 方法。

3.3. 命令参数:可以通过 CommandParameter 属性可选地定义一个命令参数。预期的参数类型在 DelegateCommand 的泛型声明中指定。当用户与控件交互时,控件会自动调用目标命令,如果提供了命令参数,它将作为参数传递给命令的 Execute 方法。

3.4. 自动调用命令:在上述示例中,当按钮被点击时,它会自动调用 ViewModel 中的 SubmitCommand。此外,如果指定了 CanExecute 委托,按钮会在 CanExecute 返回 false 时自动禁用,在返回 true 时启用。

4.向UI发送变化通知

4.1. RaiseCanExecuteChanged方法

当你需要手动更新绑定到UI元素的状态时,可以使用这个方法。例如,当IsEnabled属性的值发生变化时,在属性的setter中调用RaiseCanExecuteChanged来通知UI状态变化。

private bool _isEnabled;
public bool IsEnabled
{get { return _isEnabled; }set{SetProperty(ref _isEnabled, value);SubmitCommand.RaiseCanExecuteChanged();}
}

4.2. ObservesProperty方法

当命令需要在属性值变化时发送通知时,可以使用这个方法。使用ObservesProperty方法时,每当提供的属性值变化,DelegateCommand会自动调用RaiseCanExecuteChanged来通知UI状态变化。

public class ArticleViewModel : BindableBase
{private bool _isEnabled;public bool IsEnabled{get { return _isEnabled; }set { SetProperty(ref _isEnabled, value); }}public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand(Submit, CanSubmit).ObservesProperty(() => IsEnabled);}void Submit(){// 实现逻辑}bool CanSubmit(){return IsEnabled;}
}

注意:使用ObservesProperty方法时,可以链式注册多个属性进行观察。例如:ObservesProperty(() => IsEnabled).ObservesProperty(() => CanSave)

4.3. ObservesCanExecute方法

如果你的CanExecute是简单布尔属性的结果,你可以消除声明CanExecute委托的需要,改用ObservesCanExecute方法。ObservesCanExecute不仅会在注册的属性值变化时向UI发送通知,还会使用同一个属性作为实际的CanExecute委托。

public class ArticleViewModel : BindableBase
{private bool _isEnabled;public bool IsEnabled{get { return _isEnabled; }set { SetProperty(ref _isEnabled, value); }}public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand(Submit).ObservesCanExecute(() => IsEnabled);}void Submit(){// implement logic}
}

警告:不要尝试链式注册ObservesCanExecute方法。只能为CanExecute委托观察一个属性。

5.在命令中使用异步方法

在现代编程中,使用asyncawait调用异步方法是很常见的需求。虽然许多人的第一反应是需要一个AsyncCommand,但实际上这种假设是错误的。ICommand本质上是同步的,ExecuteCanExecute委托应该被视为事件。这意味着使用async void作为命令的语法是完全有效的。文中提供了两种使用DelegateCommand与异步方法的方法。

选项 1:

public class ArticleViewModel
{public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand(Submit);}async void Submit(){await SomeAsyncMethod();}
}

在这个选项中,Submit方法被声明为async void,这意味着它可以包含await语句来调用异步方法。DelegateCommand在执行时会调用这个Submit方法。

选项 2:

public class ArticleViewModel
{public DelegateCommand SubmitCommand { get; private set; }public ArticleViewModel(){SubmitCommand = new DelegateCommand(async () => await Submit());}Task Submit(){return SomeAsyncMethod();}
}

在这个选项中,Submit方法被声明为返回Task的普通方法,而DelegateCommand的构造函数中使用了lambda表达式async () => await Submit()来包装这个方法调用。这样,当DelegateCommand被执行时,它会调用这个lambda表达式,该表达式会异步地调用Submit方法。

这两种方法都允许你在DelegateCommand中使用异步方法,同时保持ICommand的同步特性。选择哪种方法取决于你的具体需求和偏好。

相关链接

  • 介绍(Introduction)
  • 命令(Commands)
    • 命令(Commanding)
    • 复合命令(Composite Commands)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/471922.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧建造-运用Trimble技术将梦幻水族馆变为现实【上海沪敖3D】

项目概述 西雅图水族馆耗资1.6亿美元对海洋馆进行扩建。该项目包括建造三个大型栖息地&#xff0c;每个建筑物几乎都没有直边&#xff0c;其中一个主栖息地由520立方米混凝土和355吨钢筋组成。特纳建筑公司的混凝土团队通过强大的贸易合作伙伴和创新的数字制造技术&#xff0c;…

kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署

前言&#xff1a;半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建&#xff0c;下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群&#xff08;单master节点 & 单master节点&#xff09;Prometheus监控部…

java 随机生成验证码

1.需求 实现随机生成验证码&#xff0c;验证码可能是大小写字母和数字 2.实现 写一个getCode方法实现 public static String getCode(int n){//1. 定义一个字符串&#xff0c;字符串中包含大小写字母和数字String str "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs…

Unity图形学之Blend指令

1.渲染流程&#xff1a;Blend 决定了要渲染的像素和Gbuffer里像素到底怎么取舍 2.Blend 公式&#xff1a; 3.factor可以取值的内容有&#xff1a; One 1 Zero :0 SrcColor : 要渲染的像素 SrcAlpha : 要渲染像素的 a 通道。 DstColor &#xff1a; 已经渲染在gbuffer…

林曦词典|养生

“林曦词典”是在水墨画家林曦的课堂与访谈里&#xff0c;频频邂逅的话语&#xff0c;总能生发出无尽的思考。那些悠然轻快的、微妙纷繁的&#xff0c;亦或耳熟能详的词&#xff0c;经由林曦老师的独到解析&#xff0c;意蕴无穷&#xff0c;让人受益。于是&#xff0c;我们将诸…

生成自签名证书并配置 HTTPS 使用自签名证书

生成自签名证书 1. 运行 OpenSSL 命令生成证书和私钥 在终端中输入以下命令&#xff0c;生成自签名证书和私钥文件&#xff1a; sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout self_signed.key -out self_signed.pem-x509&#xff1a;生成自签名证书。…

物料数据对接:轻易云助力聚水潭与金蝶云星空集成方案

聚水潭数据集成到金蝶云星空&#xff1a;物料对接方案 在企业信息化系统中&#xff0c;数据的高效流动和准确对接是业务运营的关键。本文将聚焦于一个具体的技术案例——如何通过轻易云数据集成平台实现聚水潭与金蝶云星空之间的物料数据对接。 本次集成任务主要涉及两个核心…

阅读2020-2023年《国外军用无人机装备技术发展综述》笔记_作战无人机和察打无人机图鉴

文献基本信息 题名作者来源发表时间2020年国外先进军用无人机技术发展综述 袁成;董晓琳;朱超磊 飞航导弹 2021-01-14 2021年国外军用无人机装备技术发展综述 朱超磊 ;袁成;杨佳会;飞航导弹 战术导弹技术2022-02-112022年国外军用无人机装备技术发展综述 朱超磊;金钰;王靖…

【C#设计模式(11)——外观模式(Facade Pattern)】

前言 外观模式隐藏了子系统的复杂性&#xff0c;简化了客户端与子系统之间的交互。 代码 public class Facade{private CommunicationModel communicationModel;private AcquisitionModel acquisitionModel;private ToolModel toolModel;public Facade(){communicationModel n…

学习日记_20241115_聚类方法(层次聚类)

前言 提醒&#xff1a; 文章内容为方便作者自己后日复习与查阅而进行的书写与发布&#xff0c;其中引用内容都会使用链接表明出处&#xff08;如有侵权问题&#xff0c;请及时联系&#xff09;。 其中内容多为一次书写&#xff0c;缺少检查与订正&#xff0c;如有问题或其他拓展…

力扣 LeetCode 239. 滑动窗口最大值(Day5:栈与队列)

解题思路&#xff1a; 始终维护deque的头元素为最大值&#xff0c;后面来的值更大就会逐一清除前面比它小的值 可以把 peek() 改为 peekFirst() &#xff0c;虽然是一个意思&#xff0c;但看起来更加清楚&#xff0c;对于双端队列能更清晰地表述具体操作 class Solution {pu…

基于GPU器件行为的创新分布式功能安全机制为智能驾驶保驾护航

作者&#xff1a;商瑞 陈娇 随着汽车智能化程度的快速提高&#xff0c;大量新的处理器和系统级芯片&#xff08;SoC&#xff09;被广泛引入到车辆中&#xff0c;无论是在驾驶还是座舱等场景&#xff0c;无论采用域控制器模式还是新兴的中央控制单元模式&#xff0c;都无一例外…

高美GULMAY高压发生器维修X射线源维修CF160

GULMAY高压发生器维修规格系列包括&#xff1a;CF,FC,CP等系列 维修类别&#xff1a;仪器仪表/无损检测仪器/其他无损检测仪器 GULMAY公司作为世界上X的工业X射线高压系统制造厂家之一,GULMAY公司拥有30多年的研发和制造经验,不但为XX射线探伤X域的用户提供种类繁多的标准型号…

动态规划-背包问题——[模版]完全背包问题

1.题目解析 题目来源 [模版]完全背包_牛客题霸_牛客 测试用例 2.算法原理 1.状态表示 与01背包相同&#xff0c;这里的完全背包也是需要一个二维dp表来表示最大价值&#xff0c;具体如下 求最大价值dp[i][j]:在[1,i]区间选择物品&#xff0c;此时总体积不大于j时的最大价值 求…

Android音视频直播低延迟探究之:WLAN低延迟模式

Android WLAN低延迟模式 Android WLAN低延迟模式是 Android 10 引入的一种功能&#xff0c;允许对延迟敏感的应用将 Wi-Fi 配置为低延迟模式&#xff0c;以减少网络延迟&#xff0c;启动条件如下&#xff1a; Wi-Fi 已启用且设备可以访问互联网。应用已创建并获得 Wi-Fi 锁&a…

Android setTheme设置透明主题无效

【问题现象】 1、首先&#xff0c;你在AndroidManifest.xml中声明一个activity&#xff0c;不给application或者activity设置android:theme, 例如这样&#xff1a; <applicationandroid:allowBackup"true"android:icon"mipmap/ic_launcher"android:lab…

基于Spring Boot的在线性格测试系统设计与实现(源码+定制+开发)智能性格测试与用户个性分析平台、在线心理测评系统的开发、性格测试与个性数据管理系统

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

摄像机视频分析软件下载LiteAIServer视频智能分析软件抖动检测的技术实现

在现代社会中&#xff0c;视频监控系统扮演着至关重要的角色&#xff0c;其可靠性和有效性在很大程度上取决于视频质量。然而&#xff0c;由于多种因素&#xff0c;如摄像机安装不当、外部环境振动或视频信号传输的不稳定&#xff0c;视频画面常常出现抖动问题&#xff0c;这不…

一文说清libc、glibc、glib的发展和关系

一 引言 在大家的技术生涯中&#xff0c;一定会遇到glib、glibc、libc这些个名词。 尤其像我这种对英文名脸盲的人&#xff0c;看着它们就头大&#xff0c;因为单从名字上看&#xff0c;也太像了&#xff0c;所以经常容易混淆。 即使翻翻网上的资料&#xff0c;看完还是有点懵…