【WPF】Prism学习(三)
Prism Commands
1.复合命令(Composite Commanding)
这段内容主要介绍了在应用程序中如何使用复合命令(Composite Commands)来实现多个视图模型(ViewModels)上的命令。以下是对这段内容的解释:
1.1. 复合命令的概念:
- 在许多情况下,ViewModel中定义的命令会绑定到相关视图中的控件上,这样用户就可以直接在视图中调用这些命令。
- 然而,在某些情况下,你可能希望从一个父视图中的控件调用一个或多个ViewModel上的命令。
1.2. 复合命令的应用场景:
- 例如,如果你的应用程序允许用户同时编辑多个项目,你可能希望允许用户使用应用程序工具栏或功能区中的单个按钮来保存所有项目。在这种情况下,"保存全部"命令将调用每个项目的ViewModel实例实现的"保存"命令。
1.3. Prism框架对复合命令的支持:
- Prism框架通过
CompositeCommand
类支持这种场景。 CompositeCommand
类表示由多个子命令组成的命令。当复合命令被调用时,会依次调用每个子命令。- 它适用于需要在UI中将一组命令表示为单个命令的情况,或者当你想要调用多个命令以实现一个逻辑命令时。
1.4. CompositeCommand
类的工作原理:
CompositeCommand
类维护一个子命令列表(DelegateCommand
实例)。CompositeCommand
类的Execute
方法简单地依次调用每个子命令的Execute
方法。CanExecute
方法类似地调用每个子命令的CanExecute
方法,但如果任何一个子命令不能执行,CanExecute
方法将返回false
。换句话说,默认情况下,只有当所有子命令都可以执行时,CompositeCommand
才能被执行。
1.5. CompositeCommand
类的位置:
CompositeCommand
可以在Prism.Commands
命名空间中找到,该命名空间位于Prism.Core
NuGet包中。
2.创建一个复合命令
复合命令是由多个子命令组成的命令,当复合命令被触发时,它的每个子命令会依次被执行。这在用户界面(UI)中表示一组命令为单个命令或者想要执行多个命令以实现一个逻辑命令时非常有用。
具体来说,创建复合命令的步骤:
- 实例化一个
CompositeCommand
对象。 - 将这个
CompositeCommand
对象作为一个属性暴露出来,这个属性可以是ICommand
或者CompositeCommand
类型。
下面是具体的代码示例:
public class ApplicationCommands
{// 创建一个私有的 CompositeCommand 实例private CompositeCommand _saveCommand = new CompositeCommand();// 将这个实例作为一个公共属性暴露出来,允许外部访问和使用这个复合命令public CompositeCommand SaveCommand{get => _saveCommand;}
}
在这个例子中,ApplicationCommands
类包含了一个名为 SaveCommand
的属性,这个属性是一个 CompositeCommand
类型的实例。这样,你就可以在应用程序的任何地方通过 ApplicationCommands.SaveCommand
来访问和使用这个复合命令,例如,将其绑定到用户界面的按钮上,当按钮被点击时,就会触发这个复合命令及其所有的子命令。
3. 全局使用复合命令(CompositeCommand)
3.1.使用依赖注入(DI)来全局使用复合命令
-
定义接口:首先,你需要定义一个接口
IApplicationCommands
,该接口包含一个SaveCommand
属性,它是一个CompositeCommand
实例。public interface IApplicationCommands {CompositeCommand SaveCommand { get; } }
-
实现接口:然后,创建一个类
ApplicationCommands
来实现这个接口,并在类中定义_saveCommand
作为CompositeCommand
的实例。public class ApplicationCommands : IApplicationCommands {private CompositeCommand _saveCommand = new CompositeCommand();public CompositeCommand SaveCommand{get => _saveCommand;} }
-
注册为单例:在你的应用程序中,需要将
ApplicationCommands
类注册为单例,这样在整个应用程序中使用的都是同一个CompositeCommand
实例。public partial class App : PrismApplication {protected override void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();} }
-
在ViewModel中注册子命令:在ViewModel的构造函数中,请求
IApplicationCommands
接口,并使用SaveCommand
来注册你的DelegateCommand
。public DelegateCommand UpdateCommand { get; private set; }public TabViewModel(IApplicationCommands applicationCommands) {UpdateCommand = new DelegateCommand(Update);applicationCommands.SaveCommand.RegisterCommand(UpdateCommand); }
3.2.使用静态类来全局使用复合命令
-
创建静态类:创建一个静态类
ApplicationCommands
,并在其中定义一个静态的SaveCommand
属性,它是一个CompositeCommand
实例。public static class ApplicationCommands {public static CompositeCommand SaveCommand = new CompositeCommand(); }
-
在ViewModel中关联子命令:在ViewModel中,将你的
DelegateCommand
与静态的ApplicationCommands
类关联起来。public DelegateCommand UpdateCommand { get; private set; }public TabViewModel() {UpdateCommand = new DelegateCommand(Update);ApplicationCommands.SaveCommand.RegisterCommand(UpdateCommand); }
为了提高代码的可维护性和可测试性,推荐使用依赖注入的方式而不是静态类。
4.绑定全局可用的复合命令(CompositeCommands)
4.1.使用依赖注入(Dependency Injection)
-
暴露IApplicationCommands:在使用依赖注入(DI)时,你需要在视图模型(ViewModel)中暴露
IApplicationCommands
接口,以便将其绑定到视图(View)。 -
设置属性:在视图模型的构造函数中请求
IApplicationCommands
实例,并设置一个类型为IApplicationCommands
的属性。public class MainWindowViewModel : BindableBase {private IApplicationCommands _applicationCommands;public IApplicationCommands ApplicationCommands{get => _applicationCommands;set => SetProperty(ref _applicationCommands, value);}public MainWindowViewModel(IApplicationCommands applicationCommands){ApplicationCommands = applicationCommands;} }
在这个例子中,
MainWindowViewModel
类有一个ApplicationCommands
属性,它在构造函数中被设置为传入的IApplicationCommands
实例。 -
在视图中绑定按钮:在XAML视图中,将按钮的
Command
属性绑定到ApplicationCommands.SaveCommand
属性。SaveCommand
是在ApplicationCommands
类中定义的。<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>
这里,按钮的
Command
属性被绑定到视图模型中的SaveCommand
属性,当按钮被点击时,会触发SaveCommand
。
4.2.使用静态类(Static Class)
-
绑定到静态ApplicationCommands类:如果你使用的是静态类方法,以下代码示例展示了如何在WPF中将按钮绑定到静态的
ApplicationCommands
类。<Button Content="Save" Command="{x:Static local:ApplicationCommands.SaveCommand}" />
在这个例子中,按钮的
Command
属性直接绑定到ApplicationCommands
类中的静态SaveCommand
属性。
5.从CompositeCommand
中注销子命令
在编程中,特别是在使用命令模式(Command Pattern)时,我们可能会创建一些命令,并将它们注册到一个复合命令(CompositeCommand
)中。这样做的好处是可以将多个命令作为一个单一的命令来处理,简化了用户界面(UI)的操作。
然而,当你的视图(View)或视图模型(ViewModel)不再需要时,比如它们即将被垃圾回收器(Garbage Collector, GC)回收,你应该从CompositeCommand
中注销这些子命令。这是因为如果这些子命令仍然被CompositeCommand
持有,它们将不会被垃圾回收,从而导致内存泄漏。内存泄漏是指程序中已分配的内存空间由于某种原因未被正确释放,导致随着时间的推移,可用内存越来越少,最终可能影响程序的性能。
public void Destroy(){_applicationCommands.UnregisterCommand(UpdateCommand);}
在这段内容中,提供了一个Destroy
方法的示例,该方法使用CompositeCommand.UnregisterCommand
方法来注销一个名为UpdateCommand
的子命令。这样做可以确保当View
或ViewModel
不再需要时,相关的命令可以被正确地从CompositeCommand
中移除,从而允许垃圾回收器回收这些对象,避免内存泄漏。
6.执行活跃视图(Active Views)上的命令
6.1. 在父视图级别协调子视图命令的执行:
- 在某些情况下,你可能希望执行所有显示视图上的命令,例如前面提到的“保存全部”(Save All)命令。
- 在其他情况下,你可能只希望在当前活跃的视图上执行命令。在这种情况下,组合命令(CompositeCommand)只会在被认为是活跃的视图上执行子命令,而不活跃的视图上的子命令则不会执行。例如,你可能想在应用程序的工具栏上实现一个“缩放”(Zoom)命令,这个命令只会导致当前活跃的项目被缩放。
6.2. IActiveAware接口:
- 为了支持上述场景,Prism提供了
IActiveAware
接口。该接口定义了一个IsActive
属性,当实现者处于活跃状态时返回true
,以及一个IsActiveChanged
事件,每当活跃状态改变时触发。
6.3. 在视图或视图模型上实现IActiveAware接口:
- 这个接口主要用于跟踪视图的活跃状态。一个视图是否活跃是由特定控件内的视图决定的。例如,在Tab控件中,有一个适配器将当前选中的标签页中的视图设置为活跃状态。
6.4. DelegateCommand类实现IActiveAware接口:
CompositeCommand
可以通过在构造函数中指定monitorCommandActivity
参数为true
来配置,以评估子DelegateCommand
的活跃状态(除了CanExecute
状态)。当这个参数设置为true
时,CompositeCommand
类在确定CanExecute
方法的返回值以及在Execute
方法中执行子命令时,会考虑每个子DelegateCommand
的活跃状态。
public class ApplicationCommands : IApplicationCommands{private CompositeCommand _saveCommand = new CompositeCommand(true);public CompositeCommand SaveCommand{get => _saveCommand;}}
6.5. CompositeCommand的行为:
- 当
monitorCommandActivity
参数为true
时,CompositeCommand
类表现出以下行为:CanExecute
:只有在所有活跃的命令都可以执行时才返回true
。不活跃的子命令将完全不被考虑。Execute
:执行所有活跃的命令。不活跃的子命令将完全不被考虑。
6.6. 在ViewModels上实现IActiveAware接口:
- 通过在ViewModels上实现
IActiveAware
接口,当视图变为活跃或不活跃时,你将得到通知。当视图的活跃状态改变时,你可以更新子命令的活跃状态。然后,当用户调用组合命令时,活跃子视图上的命令将被调用。
6.7. 示例代码:
public class TabViewModel : BindableBase, IActiveAware{private bool _isActive;public bool IsActive{get { return _isActive; }set => SetProperty(ref _isActive, OnIsActiveChanged);}public event EventHandler IsActiveChanged;public DelegateCommand UpdateCommand { get; private set; }public TabViewModel(IApplicationCommands applicationCommands){UpdateCommand = new DelegateCommand(Update);applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);}private void Update(){//实现逻辑}private void OnIsActiveChanged(){UpdateCommand.IsActive = IsActive; //set the command as activeIsActiveChanged?.Invoke(this, new EventArgs()); //invoke the event for all listeners}}
- 提供了一个
TabViewModel
的示例,展示了如何实现IActiveAware
接口,并在视图的活跃状态改变时更新子命令的活跃状态。
相关链接
- 介绍(Introduction)
- 命令(Commands)
- 命令(Commanding)
- 复合命令(Composite Commands)
相关文章:

【WPF】Prism学习(三)
Prism Commands 1.复合命令(Composite Commanding) 这段内容主要介绍了在应用程序中如何使用复合命令(Composite Commands)来实现多个视图模型(ViewModels)上的命令。以下是对这段内容的解释: …...

1+X应急响应(网络)系统加固:
系统加固: 数据库的重要性: 数据库面临的风险: 数据库加固: 业务系统加固: 安全设备加固: 网络设备加固:...

使用 Grafana api 查询 Datasource 数据
一、使用grafana 的api 接口 官方API 二、生成Api key 点击 Administration -》Users and accss -》Service accounts 进入页面 点击Add service account 创建 service account 点击Add service account token 点击 Generate token , 就可以生成 api key 了 三、进入grafana…...

【电子设计】按键LED控制与FreeRTOS
1. 安装Keilv5 打开野火资料,寻找软件包 解压后得到的信息 百度网盘 请输入提取码 提取码:gfpp 安装526或者533版本都可以 下载需要的 F1、F4、F7、H7 名字的 DFP pack 芯片包 安装完 keil 后直接双击安装 注册操作,解压注册文件夹后根据里面的图示步骤操作 打开说明 STM…...

JMeter中添加请求头
在JMeter中添加请求头的步骤如下: 1.打开HTTP信息头管理器 : 首先,你需要进入JMeter的HTTP请求组件。这可以通过在HTTP请求测试元素上右键点击,然后选择“添加 > 配置元件 > HTTP信息头管理器”来完成。 2.添加新的请求头…...

VMD + CEEMDAN 二次分解,CNN-LSTM预测模型
往期精彩内容: 时序预测:LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较 全是干货 | 数据集、学习资料、建模资源分享! EMD变体分解效果最好算法——CEEMDAN(五)-CSDN博客 拒绝信息泄露!VMD滚动分…...

【Linux系统编程】第四十六弹---线程同步与生产消费模型深度解析
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、Linux线程同步 1.1、同步概念与竞态条件 1.2、条件变量 1.2.1、认识条件变量接口 1.2.2、举例子认识条件变量 1.2.3、…...
VoIP是什么?
IP 语音 (VoIP)(Voice over Internet Protocol) 是一种通过互联网拨打电话的方法。与旧的固定电话系统不同,互联网并非设计用于在连接的人之间实时传输音频信号。必须构建专门的技术和协议才能使之成为可能,这些技术和协议构成了 …...

MySQL 中的集群部署方案
文章目录 MySQL 中的集群部署方案MySQL ReplicationMySQL Group ReplicationInnoDB ClusterInnoDB ClusterSetInnoDB ReplicaSetMMMMHAGalera ClusterMySQL ClusterMySQL Fabric 总结参考 MySQL 中的集群部署方案 MySQL Replication MySQL Replication 是官方提供的主从同步方…...

《设计模式》创建型模式总结
目录 创建型模式概述 Factory Method: 唯一的类创建型模式 Abstract Factory Builder模式 Prototype模式 Singleton模式 最近在参与一个量化交易系统的项目,里面涉及到用java来重构部分vnpy的开源框架,因为是框架的搭建,所以会涉及到像…...

Conda安装与使用中的若干问题记录
Conda安装与使用中的若干问题记录 1.Anaconda 安装失败1.1.问题复述1.2.问题解决(安装建议) 2.虚拟环境pip install未安装至本虚拟环境2.1.问题复述2.2.问题解决 3.待补充 最近由于工作上的原因,要使用到Conda进行虚拟环境的管理,…...

人力资源招聘系统的革新之路:从传统到智能的转变
在全球化与数字化交织的今天,企业间的竞争日益激烈,而人才作为企业发展的核心驱动力,其重要性不言而喻。传统的人力资源招聘方式,如依赖纸质简历、人工筛选、面对面面试等,不仅效率低下,且难以精准匹配企业…...

Python网络爬虫与数据采集实战——网络协议与HTTP
目录 1. HTTP协议简介 2. 常见的请求方法 3. 状态码含义 实际应用中的HTTP协议 1. 如何在爬虫中使用HTTP协议 2. 模拟浏览器请求与爬虫反爬虫技术 3. 高级HTTP请求 实现爬虫时HTTP协议的优化与常见问题 总结 1. HTTP协议简介 HTTP的定义与作用 HTTP(超文本…...

从零开始的c++之旅——二叉搜索树
1、二叉搜索树概念 1. ⼆叉搜索树的概念 ⼆叉搜索树⼜称⼆叉排序树,它或者是⼀棵空树,或者是具有以下性质的⼆叉树: • 若它的左⼦树不为空,则左⼦树上所有结点的值都⼩于等于根结点的值 • 若它的右⼦树不为空,则右⼦树上所有结…...

CSS回顾-基础知识详解
一、引言 在前端开发领域,CSS 曾是构建网页视觉效果的关键,与 HTML、JavaScript 一起打造精彩的网络世界。但随着组件库的大量涌现,我们亲手书写 CSS 样式的情况越来越少,CSS 基础知识也逐渐被我们遗忘。 现在,这种遗…...

Elasticsearch 查询时 term、match、match_phrase、match_phrase_prefix 的区别
Elasticsearch 查询时 term、match、match_phrase、match_phrase_prefix 的区别 keyword 与 text 区别term 查询match 查询match_phrase 查询match_phrase_prefix 查询写在最后 在讲述 es 查询时 term、match、match_phrase、match_phrase_prefix 的区别之前,先来了…...
低代码平台:跨数据库处理的重要性与实现方式
一、低代码平台概述 低代码平台作为一种创新的软件开发工具,为开发者带来了极大的便利。它具备可视化编程工具和大量预构建组件,这使得开发者无需编写大量代码就能创建应用程序,显著降低了软件开发的技术门槛。无论是专业开发人员还是业务人员…...
【jvm】如何破坏双亲委派机制
目录 1.说明2.重写ClassLoader的loadClass方法2.1 原理2.2 实现步骤2.3 注意事项 3.使用线程上下文类加载器3.1 原理3.2 实现步骤3.3 应用场景 4.利用SPI机制4.1 原理4.2 实现步骤4.3 应用场景 5.Tomcat等容器的自定义类加载器5.1 原理5.2 实现方式5.3 应用场景 1.说明 1.双亲委…...

ReactPress与WordPress:一场内容管理系统的较量
ReactPress Github项目地址:https://github.com/fecommunity/reactpress WordPress官网:https://wordpress.org/ ReactPress与WordPress:一场内容管理系统的较量 在当今数字化时代,内容管理系统(CMS)已成为…...

网络安全练习之 ctfshow_web
文章目录 VIP题目限免(即:信息泄露题)源码泄露前台JS绕过协议头信息泄露robots后台泄露phps源码泄露源码压缩包泄露版本控制泄露源码(git)版本控制泄露源码2(svn)vim临时文件泄露cookie泄露域名txt记录泄露敏感信息公布内部技术文档泄露编辑器…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...