【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)

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

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

相关文章

【Oracle篇】掌握SQL Tuning Advisor优化工具:从工具使用到SQL优化的全方位指南(第六篇,总共七篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

【一键整合包及教程】AI照片数字人工具EchoMimic技术解析

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的速度改变着我们的生活。EchoMimic&#xff0c;作为蚂蚁集团旗下支付宝推出的开源项目&#xff0c;不仅为数字人技术的发展掀开了新的一页&#xff0c;更为娱乐、教育、虚拟现实、在线会议等多个领域带…

基于Lora通讯加STM32空气质量检测WIFI通讯

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着环境污染问题的日益严重&#xff0c;空气质量的监测与管理已经…

GitLab 降级安装出现 500 错误,如何解决?

本文分享 GitLab 中文版在降级的过程中出现 500 错误的修复方法。 写在前面 强烈不建议大家自行降级&#xff0c;如果真有降级需求&#xff0c;要么自己能力过硬&#xff0c;要么寻求专业服务【https://dl.gitlab.cn/cm33bsfv】&#xff0c;要不出问题很麻烦&#xff01; 问…

2024-11-16 串的存储结构

一、顺序存储。 1.首先定一个静态数组&#xff0c;然后定义i记录串的实际长度。&#xff08;缺点&#xff1a;长度不可变&#xff09; 2.使用malloc申请动态空间&#xff0c;定义指针指向串的地址。&#xff08;需手动ferr&#xff09; 方案一&#xff1a; 数组末尾记录长度 …

PCHMI串口接收实验

插入的唯一一行代码 config1.START((Control)this, System.Reflection.Assembly.GetExecutingAssembly().GetTypes(), null);

代码随想录第46期 单调栈

这道题主要是单调栈的简单应用 class Solution { public:vector<int> dailyTemperatures(vector<int>& T) {vector<int> result(T.size(),0);stack<int> st;st.push(0);for(int i1;i<T.size();i){if(T[i]<T[st.top()]){st.push(i);}else{wh…

Spring 中的 BeanDefinitionParserDelegate 和 NamespaceHandler

一、BeanDefinitionParserDelegate Spring在解析xml文件的时候&#xff0c;在遇到<bean>标签的时候&#xff0c;我们会使用BeanDefinitionParserDelegate对象类解析<bean>标签的内容&#xff0c;包括<bean>标签的多个属性&#xff0c;例如 id name class in…

ODC 如何精确呈现SQL耗时 | OceanBase 开发者工具解析

前言 在程序员或DBA的日常工作中&#xff0c;编写并执行SQL语句如同日常饮食中的一餐一饭&#xff0c;再寻常不过。然而&#xff0c;在使用命令行或黑屏客户端处理SQL时&#xff0c;常会遇到编写难、错误排查缓慢以及查询结果可读性不佳等难题&#xff0c;因此&#xff0c;图形…

Bugku CTF_Web——No one knows regex better than me

Bugku CTF_Web——No one knows regex better than me 进入靶场 一段PHP代码 <?php error_reporting(0); $zero$_REQUEST[zero]; $first$_REQUEST[first]; $second$zero.$first; if(preg_match_all("/Yeedo|wants|a|girl|friend|or|a|flag/i",$second)){$key$…

爬虫——JSON数据处理

第三节&#xff1a;JSON数据处理 在爬虫开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;是最常见的数据格式之一&#xff0c;特别是在从API或动态网页中抓取数据时。JSON格式因其结构简单、可读性强、易于与其他系统交互而广泛应用于前端与后端的数…

OpenHarmony-1.启动流程

OpenHarmony启动流程 1.OpenHarmony 标准系统启动引导流程 OpenHarmony标准系统默认支持以下几个镜像&#xff1a; 每个开发板都需要在存储器上划分好分区来存放上述镜像&#xff0c;SOC启动时都由bootloader来加载这些镜像&#xff0c;具体过程包括以下几个大的步骤&#xf…

力扣刷题日记之150.逆波兰表达式求值

今天继续给大家分享一道力扣的做题心得今天这道题目是 150.逆波兰表达式求值 题目如下&#xff0c;题目链接&#xff1a;https://leetcode.cn/problems/evaluate-reverse-polish-notation 1&#xff0c;题目分析 这道题说是一道中等难度的题目&#xff0c;其实如果理解了其中的…

Redis五大基本类型——String字符串命令详解(命令用法详解+思维导图详解)

目录 一、String字符串类型介绍 二、常见命令 1、SET 2、GET 3、MGET 4、MSET 使用MGET 和 使用多次GET的区别 5、DEL 6、SETNX SET、SET NX和SET XX执行流程 7、INCR 8、INCRBY 9、DECR 10、DECYBY 11、INCRBYFLOAT 12、APPEND 13、GETRANGE 14、SETRANGE …

如何知道表之间的关系(为了知识图谱的构建)

今天就简单点&#xff0c;把今天花时间做的一个程序说下。 我们在做常规知识图谱的时候&#xff0c;面临一个问题就是要知道关系是如何建立。如果表的数量比较少&#xff0c;人工来做还是比较容易的。 如果有非常多的表&#xff0c;并且这些表之间的关联关系都不清楚的情况下…

【软件测试】一个简单的自动化Java程序编写

文章目录 自动化自动化概念回归测试常见面试题 自动化测试金字塔 Web 自动化测试驱动 Selenium一个简单的自动化示例安装 selenium 库使⽤selenium编写代码 自动化 自动化概念 自动的代替人的行为完成操作。自动化在生活中处处可见 生活中的自动化可以减少人力的消耗&#x…

网络学习第四篇

引言&#xff1a; 我们在第三篇的时候出现了错误&#xff0c;我们要就行排错&#xff0c;那么我们要知道一下怎么配置静态路由实现ping通&#xff0c;这样子我们才知道下一跳到底是什么&#xff0c;为什么这样子做。 实验目的 理解和掌握静态路由的基本概念和配置方法。 实…

LeetCode题解:17.电话号码的数字组合【Python题解超详细,回溯法、多叉树】,知识拓展:深度优先搜索与广度优先搜索

题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits "23" 输出…

Python爬虫项目 | 一、网易云音乐热歌榜歌曲

文章目录 1.文章概要1.1 实现方法1.2 实现代码1.3 最终效果 2.具体讲解2.1 使用的Python库2.2 代码说明2.2.1 创建目录保存文件2.2.2 爬取网易云音乐热歌榜单歌曲 2.3 过程展示 3 总结 1.文章概要 学习Python爬虫知识&#xff0c;实现简单的一个小案例&#xff0c;网易云音乐热…

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…