当前位置: 首页 > news >正文

【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)中表示一组命令为单个命令或者想要执行多个命令以实现一个逻辑命令时非常有用。

具体来说,创建复合命令的步骤:

  1. 实例化一个 CompositeCommand 对象。
  2. 将这个 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)来全局使用复合命令

  1. 定义接口:首先,你需要定义一个接口IApplicationCommands,该接口包含一个SaveCommand属性,它是一个CompositeCommand实例。

    public interface IApplicationCommands
    {CompositeCommand SaveCommand { get; }
    }
    
  2. 实现接口:然后,创建一个类ApplicationCommands来实现这个接口,并在类中定义_saveCommand作为CompositeCommand的实例。

    public class ApplicationCommands : IApplicationCommands
    {private CompositeCommand _saveCommand = new CompositeCommand();public CompositeCommand SaveCommand{get => _saveCommand;}
    }
    
  3. 注册为单例:在你的应用程序中,需要将ApplicationCommands类注册为单例,这样在整个应用程序中使用的都是同一个CompositeCommand实例。

    public partial class App : PrismApplication
    {protected override void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();}
    }
    
  4. 在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.使用静态类来全局使用复合命令

  1. 创建静态类:创建一个静态类ApplicationCommands,并在其中定义一个静态的SaveCommand属性,它是一个CompositeCommand实例。

    public static class ApplicationCommands
    {public static CompositeCommand SaveCommand = new CompositeCommand();
    }
    
  2. 在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)

  1. 暴露IApplicationCommands:在使用依赖注入(DI)时,你需要在视图模型(ViewModel)中暴露IApplicationCommands接口,以便将其绑定到视图(View)。

  2. 设置属性:在视图模型的构造函数中请求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实例。

  3. 在视图中绑定按钮:在XAML视图中,将按钮的Command属性绑定到ApplicationCommands.SaveCommand属性。SaveCommand是在ApplicationCommands类中定义的。

    <Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>
    

    这里,按钮的Command属性被绑定到视图模型中的SaveCommand属性,当按钮被点击时,会触发SaveCommand

4.2.使用静态类(Static Class)

  1. 绑定到静态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的子命令。这样做可以确保当ViewViewModel不再需要时,相关的命令可以被正确地从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.复合命令&#xff08;Composite Commanding&#xff09; 这段内容主要介绍了在应用程序中如何使用复合命令&#xff08;Composite Commands&#xff09;来实现多个视图模型&#xff08;ViewModels&#xff09;上的命令。以下是对这段内容的解释&#xff1a; …...

1+X应急响应(网络)系统加固:

系统加固&#xff1a; 数据库的重要性&#xff1a; 数据库面临的风险&#xff1a; 数据库加固&#xff1a; 业务系统加固&#xff1a; 安全设备加固&#xff1a; 网络设备加固&#xff1a;...

使用 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中添加请求头的步骤如下&#xff1a; 1.打开HTTP信息头管理器 &#xff1a; 首先&#xff0c;你需要进入JMeter的HTTP请求组件。这可以通过在HTTP请求测试元素上右键点击&#xff0c;然后选择“添加 > 配置元件 > HTTP信息头管理器”来完成。 2.添加新的请求头…...

VMD + CEEMDAN 二次分解,CNN-LSTM预测模型

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

【Linux系统编程】第四十六弹---线程同步与生产消费模型深度解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、Linux线程同步 1.1、同步概念与竞态条件 1.2、条件变量 1.2.1、认识条件变量接口 1.2.2、举例子认识条件变量 1.2.3、…...

VoIP是什么?

IP 语音 (VoIP)&#xff08;Voice over Internet Protocol&#xff09; 是一种通过互联网拨打电话的方法。与旧的固定电话系统不同&#xff0c;互联网并非设计用于在连接的人之间实时传输音频信号。必须构建专门的技术和协议才能使之成为可能&#xff0c;这些技术和协议构成了 …...

MySQL 中的集群部署方案

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

《设计模式》创建型模式总结

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

Conda安装与使用中的若干问题记录

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

人力资源招聘系统的革新之路:从传统到智能的转变

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

Python网络爬虫与数据采集实战——网络协议与HTTP

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

从零开始的c++之旅——二叉搜索树

1、二叉搜索树概念 1. ⼆叉搜索树的概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树: • 若它的左⼦树不为空&#xff0c;则左⼦树上所有结点的值都⼩于等于根结点的值 • 若它的右⼦树不为空&#xff0c;则右⼦树上所有结…...

CSS回顾-基础知识详解

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

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 的区别之前&#xff0c;先来了…...

低代码平台:跨数据库处理的重要性与实现方式

一、低代码平台概述 低代码平台作为一种创新的软件开发工具&#xff0c;为开发者带来了极大的便利。它具备可视化编程工具和大量预构建组件&#xff0c;这使得开发者无需编写大量代码就能创建应用程序&#xff0c;显著降低了软件开发的技术门槛。无论是专业开发人员还是业务人员…...

【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项目地址&#xff1a;https://github.com/fecommunity/reactpress WordPress官网&#xff1a;https://wordpress.org/ ReactPress与WordPress&#xff1a;一场内容管理系统的较量 在当今数字化时代&#xff0c;内容管理系统&#xff08;CMS&#xff09;已成为…...

网络安全练习之 ctfshow_web

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

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...