【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.xdnf.cn/news/17763.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

用go语言后端开发速查

文章目录 一、发送请求和接收请求示例1.1 发送请求1.2 接收请求 二、发送form-data格式的数据示例 用go语言发送请求和接收请求的快速参考 一、发送请求和接收请求示例 1.1 发送请求 package mainimport ("bytes""encoding/json""fmt""ne…

SpringCloud Alibaba入门简介和Nacos服务注册和配置中心

前面已经把spring cloud相关的组件都一一学了个遍,现在有点小佩服自己…本来计划今天周末好好出去玩一圈,天气太热了,39了都,还是在办公室学习吧,进行下面的springCloud Alibaba 学习吧…不废话了赶快进入正体 1. SpringCloud Alibaba入门简介 1.1 why会出现SpringCloud alib…

如何让Excel公式中的参数实现动态引用

如果你想成为Excel函数高手&#xff0c;仅仅掌握VLOOKUP和Countif等函数是远远不够的&#xff0c;起码你得学会使用INDIRECT函数&#xff0c;熟练掌握INDIRECT函数能让你从一个初学者晋级为高手&#xff0c;学会它就好比孙悟空掌握了72般变化的基本功&#xff0c;你说厉不厉害。…

【流量分析】常见webshell流量分析

免责声明&#xff1a;本文仅作分享&#xff01; 对于常见的webshell工具&#xff0c;就要知攻善防&#xff1b;后门脚本的执行导致webshell的连接&#xff0c;对于默认的脚本要了解&#xff0c;才能更清晰&#xff0c;更方便应对。 &#xff08;这里仅针对部分后门代码进行流量…

车载诊断架构 --- 关于DTC的开始检测条件

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…

掌握 Spring Boot 的最佳方法 – 学习路线图

在企业界&#xff0c;人们说“Java 永垂不朽&#xff01;”。但为什么呢&#xff1f;Java 仍然是开发企业应用程序的主要平台之一。大型公司使用企业应用程序来赚钱。这些应用程序具有高可靠性要求和庞大的代码库。根据Java开发人员生产力报告&#xff0c;62% 的受访开发人员使…

《操作系统 - 清华大学》3 -3:连续内存分配:内存碎片与分区的动态分配

文章目录 0. 概述1. 内存碎片问题2. 动态分配3. 首次适配算法4. 最优适配算法5. 最差适配算法 0. 概述 内存分配是操作系统管理过程中很重要的环节&#xff0c;首先需要考虑的是一块连续区域分配的过程&#xff0c;这个过程中会有很多问题&#xff0c;首先比较关注的一个问题是…

MySQL学习/复习3约束

一、表的常用约束 二、null、not null 三、默认值default 3.1default与null 四、注释commen 注意事项&#xff1a;desc查不到注释 五、zerofill 5.1填充0以控制宽度 六、primary_key 6.1复合主键 七、auto_increment 7.1last_insert_id() 八、unique 8.1unique与primary_key …

python视频编辑中的蒙版技术:创意与技术相结合

在数字视频编辑的世界里&#xff0c;蒙版技术是一种强大的工具&#xff0c;它允许我们在视频帧上进行精确的编辑和效果叠加。通过蒙版&#xff0c;我们可以控制哪些部分的视频内容被显示或隐藏&#xff0c;从而创造出各种视觉效果和过渡。在本文中&#xff0c;我们将探讨如何使…

文件操作和IO

目录 一. 文件预备知识 1. 硬盘 2. 文件 (1) 概念 (2) 文件路径 (3) 文件类型 二. 文件操作 1. 文件系统操作 [1] File常见的构造方法 [2] File的常用方法 [3] 查看某目录下所有的目录和文件 2. 文件内容操作 (1) 打开文件 (2) 关闭文件 (3) 读文件 (4) 写文件 …

PCB结构与组成

PCB板就是印制电路板&#xff0c;又称印刷电路板&#xff0c;是电子元器件电气连接的提供者。PCB板转化成我们所熟悉的电路板过程如下&#xff1a; 了解完定义&#xff0c;下面是我们电路板的标识 可简单的把PCB板拆分成六个部分&#xff1a;导线、铺铜、过孔、焊盘、丝印、阻焊…

OrienterNet在二维公共地图实现视觉定位的模型

论文来自MetaAI&#xff1a; https://arxiv.org/pdf/2304.02009https://arxiv.org/pdf/2304.02009github代码&#xff1a; https://github.com/facebookresearch/OrienterNet?tabreadme-ov-filehttps://github.com/facebookresearch/OrienterNet?tabreadme-ov-file 研究目…

LEAN 之 多态机制(Polymorphism,Type class)简析

LEAN 通过 类型类&#xff08;Type Class&#xff09;来提供的多态机制&#xff08;Polymorphism&#xff09;。 以∅&#xff1a;Set α 为例&#xff0c;有 Set α 实现 class EmptyCollection。 其中&#xff0c;class EmptyCollection 定义如下&#xff1a; 也就是&#xf…

【微软:多模态基础模型】(1)从专家到通用助手

欢迎关注【youcans的AGI学习笔记】原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微软&#xff1a;多模态基础模型】&#xff08;3&#xff09;视觉生成 【微…

基于java的社区捐赠物品管理系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

机器学习—建立表现基准

让我们来看看一些具体的数字&#xff0c;Jtrain和Jcv是什么&#xff0c;以及如何做出判断&#xff0c;如果学习算法具有高偏差或高方差&#xff0c;使用一个语音识别应用的例子作为讲解。 很多在手机上进行网络搜索的用户会使用语音识别&#xff0c;而不是在手机上的小键盘上打…

阮一峰科技爱好者周刊(第 325 期)推荐工具:一个基于 Next.js 的博客和 CMS 系统

近期&#xff0c;阮一峰在科技爱好者周刊第 325 期中推荐了一款开源工具——ReactPress&#xff0c;ReactPress一个基于 Next.js 的博客和 CMS 系统&#xff0c;可查看 demo站点。&#xff08;fecommunity 投稿&#xff09; ReactPress&#xff1a;一款值得推荐的开源发布平台 …

大学语文教材电子版(第十一版)教学用书PDF及课件

大学语文课件&#xff1a;https://caiyun.139.com/m/i?005CiDusEVWnR 《大学语文》&#xff08;第十一版&#xff09;主编&#xff1a;徐中玉 齐森华 谭帆。 大学语文教材电子版教师用书PDF第一课《齐桓晋文之事》艺术赏析&#xff1a; 孟子四处游说&#xff0c;养成善辩的…

RK356x-8:Wifi模块AP6xxx配置与调试

本文记录如何根据原理图&#xff0c;配置和调试RK356x&#xff08;测试用RK3566&#xff09;主板上wifi/蓝牙模块&#xff08;测试用AP6212&#xff0c;rkwifibt&#xff09;&#xff0c;使其能正确连网。 1.配置SOC接口 1.1 查看原理图&#xff0c;看看wifi模块用的接口是什…

Java基础——网络编程

可以让设备中的程序与网络上其他设备中的程序进行数据交互&#xff08;实现网络通信的&#xff09;。 1. 基本的通信架构 基本的通信架构有2种形式&#xff1a;CS架构&#xff08;Client客户端/Server服务端&#xff09;、BS架构&#xff08;Browser浏览器/Server服务端&…