【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 active
            IsActiveChanged?.Invoke(this, new EventArgs()); //invoke the event for all listeners
        }
    }
  • 提供了一个TabViewModel的示例,展示了如何实现IActiveAware接口,并在视图的活跃状态改变时更新子命令的活跃状态。

相关链接

  • 介绍(Introduction)
  • 命令(Commands)
    • 命令(Commanding)
    • 复合命令(Composite Commands)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

模型压缩相关技术概念澄清(量化/剪枝/知识蒸馏)

1.模型压缩背景 随着深度学习技术的不断发展&#xff0c;模型的规模和复杂度也随之增加。大型模型往往具有更高的精度和更强的泛化能力&#xff0c;但在实际应用中&#xff0c;模型的大小却成为了一个制约因素。模型体积过大会导致存储、传输和推理速度等方面的瓶颈&#xff0…

‌EAC(Estimate at Completion)和ETC(Estimate to Complete)

‌EAC 预计完工成本ETC 预计尚需成本Estimate at CompletionEstimate to Complete完成预估完工时尚需成本估算 EAC ETC ACETC EAC – AC 预测项目总成本&#xff0c;包含了到目前为止实际发生的成本&#xff08;AC&#xff09;和预计将发生的成本。如果EAC大于BAC&#xf…

计算机网络 (6)物理层的基本概念

前言 计算机网络物理层是OSI模型&#xff08;开放式系统互联模型&#xff09;中的第一层&#xff0c;也是七层中的最底层&#xff0c;它涉及到计算机网络中数据的物理传输。 一、物理层的主要任务和功能 物理层的主要任务是处理物理传输介质上的原始比特流&#xff0c;确保数据…

探索大规模语言模型(LLM)在心理健康护理领域中的应用与潜力

概述 心理健康是公共卫生最重要的领域之一。根据美国国家精神卫生研究所&#xff08;NIMH&#xff09;的数据&#xff0c;到 2021 年&#xff0c;22.8% 的美国成年人将患上某种形式的精神疾病。在全球范围内&#xff0c;精神疾病占非致命性疾病负担的 30%&#xff0c;并被世界…

深度学习之GAN应用

1 GAN的应用&#xff08;文本生成&#xff09; 1.1 GAN为什么不适合文本任务&#xff1f; ​ GAN在2014年被提出之后&#xff0c;在图像生成领域取得了广泛的研究应用。然后在文本领域却一直没有很惊艳的效果。主要在于文本数据是离散数据&#xff0c;而GAN在应用于离散数据时…

15分钟学 Go 实战项目五 :简单电子商务网站(3W字完整例子)

简单的电子商务网站开发实战 项目概述 目标 实现用户注册登录功能开发商品浏览和搜索功能实现购物车管理完成订单处理流程 技术栈 类别技术选择说明Web框架Gin高性能HTTP框架数据库MySQL存储用户和商品信息缓存Redis购物车和会话管理ORMGORM数据库操作认证JWT用户身份验证…

C++- 基于多设计模式下的同步异步日志系统

第一个项目:13万字,带源代码和详细步骤 目录 第一个项目:13万字,带源代码和详细步骤 1. 项目介绍 2. 核心技术 3. 日志系统介绍 3.1 为什么需要⽇志系统 3.2 ⽇志系统技术实现 3.2.1 同步写⽇志 3.2.2 异步写⽇志 4.知识点和单词补充 4.1单词补充 4.2知识点补充…

【AlphaFold3】开源本地的安装及使用

文章目录 安装安装DockerInstalling Docker on Host启用Rootless Docker 安装 GPU 支持安装 NVIDIA 驱动程序安装 NVIDIA 对 Docker 的支持 获取 AlphaFold 3 源代码获取基因数据库获取模型参数构建将运行 AlphaFold 3 的 Docker 容器 参考 AlphaFold3: https://github.com/goo…

【提高篇】3.4 GPIO(四,工作模式详解 下)

五,模拟输入输出 5.1 模拟功能 上下拉电阻断开,施密特触发器关闭,双 MOS 管也关闭。该模式用于 ADC 采集或者 DAC 输出,或者低功耗下省电。但要注意的是 GPIO本身并不具备模拟输出输入的功能。 5.2 模拟功能的特点 上拉电阻关闭下拉电阻关闭施密特触发器关闭双MOS管不…

向潜在安全信息和事件管理 SIEM 提供商提出的六个问题

收集和解读数据洞察以制定可用的解决方案是强大网络安全策略的基础。然而&#xff0c;组织正淹没在数据中&#xff0c;这使得这项任务变得复杂。 传统的安全信息和事件管理 ( SIEM ) 工具是组织尝试使用的一种方法&#xff0c;但由于成本、资源和可扩展性等几个原因&#xff0…

领域驱动系列-浅析VO、DTO、DO、PO

一、概念介绍 POJO&#xff08;plain ordinary java object&#xff09; &#xff1a;简单java对象&#xff0c;个人感觉POJO是最常见最多变的对象&#xff0c;是一个中间对象&#xff0c;也是我们最常打交道的对象。一个POJO持久化以后就是PO&#xff0c;直接用它传递、传递过…

网站部署到IIS后,数据库登录失败

1.数据库-安全性-登录名-NT AUTHORITY\SYSTEM-属性 2.选择用户映射选项---在里面将我们要访问的数据库选中 3.先别点确定---再选择我们刚才选择的哪个数据库,在下面的数据库角色成员身份里要选择db_owner权限

paddle表格识别数据制作

数据格式 其中主要数据有两个一个表格结构的检测框&#xff0c;一个是tokens&#xff0c;注意的地方是 1、只能使用双引号&#xff0c;单引号不行 2、使用带引号的地方是tokens里面 "<tr>", "<td", " colspan2", ">",&quo…

FPGA 第6讲 简单组合逻辑多路选择器

时间&#xff1a;2024.11.11-11.14 一、学习内容 1.组合逻辑 组合逻辑是VerilgHDL设计中一个重要组成部分。从电路本质上讲&#xff0c;组合逻辑电路的特点是输出信号只是当前时刻输入信号的函数&#xff0c;与其他时刻的输入状态无关&#xff0c;无存储电路&#xff0c;也没…

Elasticsearch 8.16.0:革新大数据搜索的新利器

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

Mysql-DQL条件查询

文章目录 条件查询比较运算符逻辑运算符范围like 关键字排序单列顺序组合排序 聚合函数分组基本的分组流程参数的区别 limit 语句limit 语法格式limit 的使用场景 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Mysql专栏&#xff1a;点击&#xff01; ⏰…

华为云租户网络-用的是隧道技术

1.验证租户网络是vxlan 2.验证用OVS 2.1控制节点VXLAN 本端ip&#xff08;local ip&#xff09;192.168.31.8 2.2计算节点VXLAN 本端ip&#xff08;local ip&#xff09;192.168.31.11 计算节点用的是bond0做隧道网络 2.3查看bond文件是否主备模式

go 集成swagger 在线接口文档

安装swaggo go install github.com/swaggo/swag/cmd/swaglatest 编写swag import ("github.com/gin-gonic/gin""goWeb/internal/service""goWeb/model/response" )// UserRouter 路由 func UserRouter(ctx *gin.RouterGroup) {ctx.GET("/…

《Python网络安全项目实战》项目6 编写密码工具程序

《Python网络安全项目实战》项目6 编写密码工具程序 项目6 编写密码工具程序任务6.1 猜数字游戏任务描述任务分析任务实施6.1.1 编写基本的猜数字程序6.1.3 测试并修改程序6.1.4 给程序增加注释 任务拓展任务实施6.2.1 生成随机密码6.2.4 菜单功能 相关知识1. 密码字典2. 密码字…

IQ Offset之工厂实例分析

有个产品 其方块图如下: FEM全名为Front End Module 详情可参照这篇 [1] WIFI前端模块的解析 这边就不赘述 而在工厂大量生产时 有一块板子 其Chain1的EVM Fail 分析Log后 发现其IQ Offset的值 比Chain2/Chain3/Chain4 还要来得差 请问 问题是出在收发器? 还是…