【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中的Execute
和CanExecute
方法。这意味着,当你在UI中触发一个命令时,DelegateCommand
会调用ViewModel中相应的方法。
2.2. 你可以通过DelegateCommand
类的构造函数来指定这些委托。例如,下面的代码示例展示了如何通过指定委托到ViewModel中的Submit
和CanSubmit
方法来构造一个代表提交命令的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
类是一个泛型类型。类型参数指定了传递给Execute
和CanExecute
方法的命令参数的类型。在上面的例子中,命令参数是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
避免使用值类型作为参数,如果需要使用值类型参数时,应该如何处理以避免潜在的问题:
- DelegateCommand避免使用值类型:
DelegateCommand
这个类在设计时故意不使用值类型(如int
、double
、bool
等)作为参数类型。这是因为ICommand
接口接受的是一个对象类型的参数。- 值类型参数可能导致意外行为:如果在XAML初始化时,命令绑定调用了
CanExecute(null)
,并且T
是一个值类型,那么可能会导致一些意料之外的行为。这是因为值类型在默认情况下会被初始化为它们的默认值(如int
的默认值是0),这可能会导致命令的执行逻辑出现问题。- 默认值问题:考虑过使用
default(T)
作为解决方案,但最终被拒绝了。原因是实现者将无法区分一个有效的值和一个默认值。例如,如果T
是int
,那么default(int)
是0,但实现者可能无法确定0是一个有效的参数值还是一个默认值。- 使用可空类型:如果你确实需要使用值类型作为参数,那么必须将其转换为可空类型(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.在命令中使用异步方法
在现代编程中,使用async
和await
调用异步方法是很常见的需求。虽然许多人的第一反应是需要一个AsyncCommand
,但实际上这种假设是错误的。ICommand
本质上是同步的,Execute
和CanExecute
委托应该被视为事件。这意味着使用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)
相关文章:

【WPF】Prism学习(二)
Prism Commands 1.命令(Commanding) 1.1. ViewModel的作用: ViewModel不仅提供在视图中显示或编辑的数据,还可能定义一个或多个用户可以执行的动作或操作。这些用户可以通过用户界面(UI)执行的动作或操作…...

【鸿蒙开发】第二十一章 Location位置服务
目录 1 简介 1.1 Location Kit简介 1.2 运作机制 1.3 约束与限制 2 位置服务开发 2.1 申请位置权限开发指导 2.1.1 场景概述 2.2 获取设备的位置信息开发指导 2.2.1 场景概述 2.2.2 接口说明 2.2.3 开发步骤 2.3(逆)地理编码转化开发指导 2.…...

《目标检测》R-CNN网络基础(RCNN,Fast-RCNN)
文章目录 1.Overfeat模型2.RCNN网络2.1 算法流程2.1.1 候选区域的生成(了解,已经不再使用了)2.1.2 CNN网络提取特征2.1.3 目标分类(SVM)2.1.4 目标回归(线性回归修正坐标)2.1.5 预测过程 2.2 算…...

iOS中的定位实现(逆地理编码)及Info.plist位置权限详解
引言 在现代移动应用开发中,位置服务已经成为不可或缺的一部分。无论是地图导航、社交分享,还是基于位置的个性化推荐,位置数据都为用户提供了更加丰富和智能的体验。然而,随着用户隐私保护的不断加强,iOS对位置权限的…...

【从零开始的LeetCode-算法】3270. 求出数字答案
给你三个 正 整数 num1 ,num2 和 num3 。 数字 num1 ,num2 和 num3 的数字答案 key 是一个四位数,定义如下: 一开始,如果有数字 少于 四位数,给它补 前导 0 。答案 key 的第 i 个数位(1 < …...

Web认证机制 Cookie、Token、Session、JWT、OAuth2 解析
标题 一、Cookie二、Session三、Token四、JWTSSO(单点登录) 五、OAuth2如何设计权限系统区别总结 Cookie、Token、Session 和 JWT 都是在 Web 开发中常用的身份验证和授权技术,它们各有优缺点,适用于不同的场景。 Cookie 简单易用…...

Docker 基础命令介绍和常见报错解决
介绍一些 docker 可能用到的基础命令,并解决三个常见报错: 权限被拒绝(Permission Denied)无法连接到 Docker 仓库(Timeout Exceeded)磁盘空间不足(No Space Left on Device) 命令以…...

如何轻松导出所有 WordPress URL 为纯文本格式
作为一名多年的 WordPress 使用者,我深知管理一个网站的复杂性。从迁移网站、设置重定向到整理内容结构,每一步都需要精细处理。而拥有所有 URL 的清单,不仅能让这些工作变得更加简单,还能为后续的管理提供极大的便利。其实&#…...

【进程概念精讲】
Susan,在那命运月台前面,再上车,春天开始落叶.................................................................. 文章目录 前言 一、【认识进程】 1、【进程基本概念引入】 2、【进程的描述与组织——进程控制块(PCB)与进程…...

帽子矩阵--记录
帽子矩阵 H是一个重要的统计工具,用于评估数据点对模型拟合结果的影响。通过计算帽子矩阵的对角线元素(杠杆值),我们可以识别出高杠杆点,这些点对模型的影响较大,可能需要特别关注。...

MySQL深入:B+树的演化、索引和索引结构
提示:内容是读《MySQL技术内幕:InnoDB存储引擎》,笔记摘要 文章目录 二叉查找树平衡二叉树(AVL) B树(BTree)B树(BTree)InnoDB B树索引索引结构(InnoDB B树)B树存放的数据量 二叉查找树 在二叉查找树中,左子…...

axios 实现 无感刷新方案
实现思路 首次登录前端通过接口获取到两个 token;分别是 accessToken、refreshToken; accessToken:正常请求需要传递的 token ;refreshToken:当某个请求 401 ,就可以通过 refreshToken 获取到新的 accessToken 特殊场…...

Python 三种方式实现自动化任务
在这篇文章中,我们将介绍一些用Python实现机器人过程自动化的包。机器人流程自动化(Robotic process automation,简称RPA)是指将鼠标点击和键盘按压自动化的过程,即模拟人类用户的操作。RPA用于各种应用程序࿰…...

新型创业模式:退休创业。没有工资,不用投资,有时间就干,不强制做,赚钱按贡献分。
这种“退休创业”的创业模式具有独特的吸引力和灵活性,适合那些已退休但希望继续贡献社会价值、赚取额外收入且无需承担太多责任的群体。以下是一个详细的设计思路: 模式概述 目标人群:退休人员,具有一定技能或经验,但…...
Android 项目依赖库无法找到的解决方案
目录 错误信息解析 解决方案 1. 检查依赖版本 2. 检查 Maven 仓库配置 3. 强制刷新 Gradle 缓存 4. 检查网络连接 5. 手动下载依赖 总结 相关推荐 最近,我在编译一个 Android 老项目时遇到了一个问题,错误信息显示无法找到 com.gyf.immersionba…...

在Node.js中如何使用TypeScript
第一步:创建一个Node.js项目的package.json文件 npm init -y第二步:添加TypeScript、添加node.d.ts npm install typescript -D npm install types/node -D第三步:初始化一个tsconfig.json文件 npx tsc --init --rootDir src --outDir lib…...

链表两数加python
一、问题描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个…...

免费的可以薅羊毛的cloudflare反向代理教程
cloudflare-reverse-proxy 项目代码: https://github.com/EASTCATV/cloudflare-reverse-proxy 本项目是cloudflare反向代理。在cloudflare网站中新建worker,把worker.js文件中的内容复制进去即可使用。 使用方法为在任意url前面加上https://你的域名/proxy/ 即可…...

【每日刷题】Day155
【每日刷题】Day155 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. LCR 108. 单词接龙 - 力扣(LeetCode) 2. 675. 为高尔夫球比赛砍树 - 力扣(…...

EXCEL延迟退休公式
如图: A B为手工输入 C2EOMONTH(A2,B2*12) D2EOMONTH(C2,IF(C2>DATEVALUE("2025-1-1"),INT((DATEDIF(DATEVALUE("2025-1-1"),C2,"m")4)/4),0)) E2EOMONTH(A2,B2*12IF(EOMONTH(A2,B2*12)>DATEVALUE("2025-1-1"),INT(…...

开源对象存储新选择:在Docker上部署MinIO并实现远程管理
文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器,可以在各种环境中运行,例如本地、Docker容器、Kubernetes集群等。它兼…...

Spring Cloud生态圈
目录 Spring Cloud生态圈 核心组件 其他组件 总结 Spring Cloud Alibaba生态圈 核心组件 其他特性 Spring Cloud生态圈 Spring Cloud生态圈是一个为微服务架构提供全方位支持的解决方案集合。它涵盖了多个关键组件和服务,旨在帮助开发者快速构建、部署和管理…...

AI视觉小车基础--4.舵机控制(云台控制)
一、实验准备 控制连接在扩展板上的舵机。如下图所示,按键KEY1为板载元器件,所以不需要外接其他设备。 二、运行代码 # Import the Raspbot library import time from Raspbot_Lib import Raspbot from ipywidgets import interact import ipywidgets a…...

【Rust中的项目管理】
Rust中的项目管理 前言Package,Crate,Module &use ,Path通过代码示例解释 Crate,Module ,use,Path创建一个package:代码组织化skin.rs 中的代码struct & enum 相对路径和绝对路径引用同…...

【原创】如何备份和还原Ubuntu系统,非常详细!!
前言 我在虚拟机装了一个xfce4的Ubuntu桌面版,外加输入法、IDEA等,我想将这个虚拟机里的系统直接搬到物理机中,那我可以省的再重新装一遍、配置xfce4桌面、修改一堆快捷键还有配置idea了,那直接说干就干。 本教程基于Ubuntu24.0…...

成都栩熙酷网络科技抖音小店是真的
近年来,随着短视频平台的崛起,抖音小店作为一种新兴的购物模式,迅速吸引了大量消费者和商家的关注。在这一潮流中,成都栩熙酷网络科技有限公司(以下简称“栩熙酷”)凭借其敏锐的市场洞察力和强大的技术实力…...

Python 爬虫数据清洗与存储:基础教程
Python 爬虫数据清洗与存储:基础教程 在爬虫数据获取完成后,数据往往是“原始”的,不适合直接使用。清洗和存储是将爬取到的原始数据转化为有用信息的关键步骤。本文将系统地介绍 Python 中进行数据清洗与存储的基本方法,帮助新手…...

ssm122基于Java的高校教学业绩信息管理系统+jsp(论文+源码)_kaic
毕 业 设 计(论 文) 题目:高校教学业绩信息管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本高校教学…...

Java 基础知识
一.泛型编程 1. 泛型的概念和作用是什么? 概念:泛型(Generics)是在 JDK 5.0 引入的新特性,允许在定义类、接口和方法时使用类型参数。类型参数在使用时被具体的类型替换。作用: 类型安全性:避…...

深入探索 React Hooks:原理、用法与性能优化全解
一、引言 在现代 React 开发领域,Hooks 已成为不可或缺的一部分,赋予函数组件强大功能,使其能胜任复杂任务。本文将全面剖析 React Hooks,助您深入理解并熟练运用。 二、React Hooks 是什么 (一)Hooks 出现的背景 早期 React 主要依赖类组件,其通过this.state管理状…...