【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.mzph.cn/pingmian/61101.shtml

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

相关文章

学者观察 | 元计算、人工智能和Web 3.0——山东大学教授成秀珍

导语 成秀珍教授提出元计算是在开放的零信任环境下整合算力资源打通数据壁垒构建自进化智能的新质生产力技术&#xff0c;是一种新计算范式&#xff1b;区块链是Web3.0的核心技术之一&#xff0c;有助于保障开放零信任环境下&#xff0c;用户、设备和服务间去中心化数据流通的…

学习笔记022——Ubuntu 安装 MySQL8.0版本踩坑记录

目录 1、查看可安装 MySQL 版本 2、Ubuntu安装 MySQL8.0 3、MySQL8.0 区分大小写问题 4、MySQL8.0 设置sql_mode 5、MySQL8.0 改端口33060&#xff08;个人遇到问题&#xff09; 1、查看可安装 MySQL 版本 ## 列出可用的MySQL版本&#xff08;列出所有可用的MySQL版本以…

「AI Infra 软件开源不是一个选项,而是必然」丨云边端架构和 AI Infra专场回顾@RTE2024

在人工智能和开源技术蓬勃发展的当下&#xff0c;AI Infra 项目正经历着日新月异的变革。从跨平台运行时到云边端 AI 基础设施&#xff0c;再到多模态知识助手&#xff0c;创新浪潮席卷而来。这些进步不仅显著提升了技术指标&#xff0c;也为实时音视频处理、边缘计算、大模型应…

《Python制作动态爱心粒子特效》

一、实现思路 粒子效果&#xff1a; – 使用Pygame模拟粒子运动&#xff0c;粒子会以爱心的轨迹分布并运动。爱心公式&#xff1a; 爱心的数学公式&#xff1a; x16sin 3 (t),y13cos(t)−5cos(2t)−2cos(3t)−cos(4t) 参数 t t 的范围决定爱心形状。 动态效果&#xff1a; 粒子…

免费实时图片编辑工具:MagicQuill

参看&#xff1a; https://huggingface.co/spaces/AI4Editing/MagicQuill 人工智能交互式图像编辑&#xff1a;可以制定涂改增加删除

web——upload-labs——第九关——特殊字符::$DATA绕过

特殊字符::$DATA绕过 典型绕过场景 在一些系统中&#xff0c;::$DATA 被用于绕过文件路径的限制。比如&#xff1a; 路径过滤绕过&#xff1a;如果系统有某种机制来检查和限制文件路径&#xff08;例如&#xff0c;禁止访问某些系统目录或敏感文件&#xff09;&#xff0c;通…

本地部署 excalidraw

本地部署 excalidraw 0. 引言1. 本地部署 excalidraw2. 访问 excalidraw 0. 引言 Excalidraw 编辑器是一款开源虚拟手绘白板&#xff0c;支持协作且端到端加密。 1. 本地部署 excalidraw git clone https://github.com/excalidraw/excalidraw.git; cd excalidrawvi docker-c…

《Java核心技术 卷I》用户界面AWT事件继承层次

AWT事件继承层次 EventObject类有一个子类AWTEvent&#xff0c;它是所有AWT事件类的父类。 Swing组件会生成更多其他事件对象&#xff0c;都直接拓展自EventObject而不是AWTEvent。 AWT将事件分为底层(low-level)事件和语义事件。 语义事件&#xff1a;表示用户的动作事件&…

三周精通FastAPI:42 手动运行服务器 - Uvicorn Gunicorn with Uvicorn

官方文档&#xff1a;Server Workers - Gunicorn with Uvicorn - FastAPI 使用 fastapi 运行命令 可以直接使用fastapi run命令来启动FastAPI应用&#xff1a; fastapi run main.py如创建openapi.py文件&#xff1a; from fastapi import FastAPIapp FastAPI(openapi_url&…

整理iPhone空间:iphone怎么删除相簿

随着时间的积累&#xff0c;我们的iPhone中不仅会堆积大量照片&#xff0c;还可能会有多个不再需要的相簿。这些相簿不仅占用存储空间&#xff0c;还可能使相册应用变得杂乱无章。本文将探讨iphone怎么删除相簿&#xff0c;并介绍精简iPhone相册的技巧&#xff0c;使你的相册管…

路漫漫其修远兮,吾将上下而求索---第一次使用github的过程记录和个人感受

文章目录 1.仓库位置2.新建仓库3.配置仓库4.克隆和上传5.推荐文章和我的感受 1.仓库位置 这个仓库的位置就是在我们的这个个人主页的右上角&#xff1b;如果是第一次注册账号的话&#xff0c;这个主页里面肯定是不存在仓库的&#xff0c;需要我们自己手动的进行创建&#xff1…

ICML24最新开源时序基础模型MOMENT

论文标题&#xff1a;MOMENT: A Family of Open Time-series Foundation Models 论文链接&#xff1a;https://arxiv.org/pdf/2402.03885 前言 当前时间序列数据上预训练大型模型面临以下挑战&#xff1a;(1) 缺乏大型且统一的公共时间序列数据集&#xff0c;(2) 时间序列特…

SpringBoot Data Redis连接Redis-Cluster集群

使用SpringBoot Data Redis无法连接Redis-Cluster集群 最近在研究系统高并发下的缓存架构&#xff0c;因此自己在自己买的云服务器上搭建好Redis 5.0 版本的集群后&#xff0c;使用springboot的 RedisTemplate连接是发现总是访问不到集群节点。上网百度了发现没有好的解决办法&…

鸿蒙中服务卡片数据的获取和渲染

1. 2.在卡片中使用LocalStorageProp接受传递的数据 LocalStorageProp("configNewsHead") configNewsHeadLocal: ConfigNewsHeadInfoItem[] [] 注意&#xff1a;LocalStorageProp括号中的为第一步图片2中的键 3.第一次在服务卡片的第一个卡片中可能会获取不到数据…

ARM64环境部署EFK8.15.3收集K8S集群容器日志

环境规划 主机IP系统部署方式ES版本CPU架构用户名密码192.168.1.225Ubuntu 22.04.4 LTSdockerelasticsearch:8.15.3ARM64elasticllodyi4TMmZD ES集群部署 创建持久化目录(所有节点) mkdir -p /data/es/{data,certs,logs,plugins} mkdir -p /data/es/certs/{ca,es01}服务器…

应用系统开发(12) Zync中实现数字相敏检波

在 Xilinx Zynq 系列(如 Zynq-7000 或 Zynq UltraScale+)中实现数字相敏检波(DSP,Digital Synchronous Detection)可以通过硬件(PL部分,FPGA逻辑)和软件(PS部分,ARM Cortex-A 处理器)的协同工作来实现。以下是一个详细的设计方法,包括基本原理和 Zynq 的实现步骤。…

力扣hot100-->二分查找

目录 二分查找 1. 33. 搜索旋转排序数组 2. 34. 在排序数组中查找元素的第一个和最后一个位置 3. 240. 搜索二维矩阵 II 3. 287. 寻找重复数 二分查找 1. 33. 搜索旋转排序数组 中等 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&am…

南京邮电大学《智能控制技术》课后作业

一、问题一 复现二输入单输出模糊控制系统&#xff0c;改动其中一到两个环节&#xff08;隶属度设置、规则等&#xff09;&#xff0c;对比修改前后控制效果。 定义模糊 %Fuzzy Control for water tank clear all; close all;anewfis(fuzz_tank);%Fuzzy Inference System stru…

苹果ASA归因对接以及API接入

一、归因概要 广告归因&#xff0c;目的是用于衡量广告带来的激活用户的成本以及后续进一步的用户质量表现。 Apple Ads 广告平台是基于 App Store&#xff08;站内广告&#xff09;&#xff0c;同时属于自归因平台&#xff08;通常称为 SAN&#xff09;。这两个因素&#xff…

hhdb数据库介绍(9-18)

Oracle兼容性说明 数据类型兼容 本节主要介绍 HHDB Server与Oracle 数据库中数据类型的详细兼容对比信息。 比较项Oracle数据库数据类型HHDB Server数据类型对应项/替代项字符串/字符VARCHAR2( n )VARCHAR( n )字符串/字符NVARCHAR2( n )VARCHAR( n ) character set utf8字符…