Composite Commands

在许多情况下,视图模型定义的命令将绑定到关联视图中的控件,以便用户可以直接从视图中调用该命令。但是,在某些情况下,您可能希望能够从应用程序UI的父视图中的控件调用一个或多个视图模型上的命令。

例如,如果您的应用程序允许用户同时编辑多个项目,您可能希望允许用户使用应用程序工具栏或功能区中的按钮所代表的单个命令来保存所有项目。在这种情况下,Save All命令将调用每个项目的视图模型实例实现的每个Save命令,如下图所示。

Prism通过CompositeCommand课程支持这种情况。

CompositeCommand类表示从多个子指令构成的指令。调用复合命令时,将依次调用其每个子命令。在需要在UI中将一组命令表示为单个命令或者要调用多个命令来实现逻辑命令的情况下,它非常有用。

CompositeCommand类维护子类命令列表 (DelegateCommand实例)。CompositeCommand类的Execute方法依次调用每个子类的Execute命令方法。CanExecute方法类似地调用每个子命令的CanExecute方法,但是如果无法执行任何子命令,则该CanExecute方法将返回false。换句话说,默认情况下,CompositeCommand只有在可以执行所有子命令时才能执行。

[Using Composite Commands视频教程](Prism.assets/Prism - Using Composite Commands.mp4)

创建Composite Commands

要创建复合命令,请实例化一个CompositeCommand实例,然后将其公开为ICommandComponsiteCommand属性。

public class ApplicationCommands
{
private CompositeCommand _saveCommand = new CompositeCommand();
public CompositeCommand SaveCommand
{
get { return _saveCommand; }
}
}

使得Composite Commands全局可用

通常,CompositeCommands在整个应用程序中共享,需要全局可用。当您CompositeCommand在整个应用程序中使用同一个CompositeCommand实例注册子命令时,这一点很重要。这需要在应用程序中将CompositeCommand作为单例取消。这可以通过使用依赖注入(DI)或将CompositeCommand定义为静态类来完成。

使用依赖注入

定义CompositeCommands的第一步是创建一个接口。

public interface IApplicationCommands
{
CompositeCommand SaveCommand { get; }
}

接下来,创建一个实现该接口的类。

public class ApplicationCommands : IApplicationCommands
{
private CompositeCommand _saveCommand = new CompositeCommand();
public CompositeCommand SaveCommand
{
get { return _saveCommand; }
}
}

定义ApplicationCommands类后,必须将其注册为容器的单例。

public partial class App : PrismApplication
{
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();
}
}

接下来,请求IApplicationCommandsViewModel构造函数中的接口。一旦有了ApplicationCommands该类的实例,现在可以使用适当的CompositeCommand注册DelegateCommands。

public DelegateCommand UpdateCommand { get; private set; }

public TabViewModel(IApplicationCommands applicationCommands)
{
UpdateCommand = new DelegateCommand(Update);
applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
}

使用静态类

创建一个代表CompositeCommands的静态类

public static class ApplicationCommands
{
public static CompositeCommand SaveCommand = new CompositeCommand();
}

在ViewModel中,将子命令与静态ApplicationCommands类关联。

    public DelegateCommand UpdateCommand { get; private set; }

    public TabViewModel()
{
UpdateCommand = new DelegateCommand(Update);
ApplicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
}

注意

为了提高代码的可维护性和可测试性,建议您使用可靠性注入方法。

绑定全局可用命令

一旦创建了CompositeCommands,就必须将它们绑定到UI元素以调用命令。

使用依赖注入 (Dependency Injection)

使用DI时,必须将IApplicationCommands暴露给View。在视图的ViewModel中,请IApplicationCommands在构造函数中请求并IApplicationCommands为该实例设置type属性。

public class MainWindowViewModel : BindableBase
{
private IApplicationCommands _applicationCommands;
public IApplicationCommands ApplicationCommands
{
get { return _applicationCommands; }
set { SetProperty(ref _applicationCommands, value); }
} public MainWindowViewModel(IApplicationCommands applicationCommands)
{
ApplicationCommands = applicationCommands;
}
}

在视图中,将按钮绑定到ApplicationCommands.SaveCommand属性。这SaveCommand是在ApplicationCommands类上定义的属性。

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

使用静态类

如果您使用的是静态类方法,则以下代码示例演示如何将按钮绑定到WPF中的静态ApplicationCommands类。

<Button Content="Save" Command="{x:Static local:ApplicationCommands.SaveCommand}" />

取消注册命令

如前面的示例所示,使用该CompositeCommand.RegisterCommand方法注册子命令。但是,当您不再希望响应CompositeCommand或者您要销毁View / ViewModel以进行垃圾回收时,您应该使用该CompositeCommand.UnregisterCommand方法取消注册子命令。

public void Destroy()
{
_applicationCommands.UnregisterCommand(UpdateCommand);
}
重要

您必须从CompositeCommand不再需要View / ViewModel(为GC准备好)时取消注册您的命令。否则你会引入内存泄漏。

在活动视图上执行命令

父视图级别的复合命令通常用于协调如何调用子视图级别的命令。在某些情况下,您将需要执行所有显示视图的命令,如前面所述的Save All命令示例中所示。在其他情况下,您将希望仅在活动视图上执行该命令。在这种情况下,复合命令将仅对被视为活动的视图执行子命令; 它不会在非活动的视图上执行子命令。例如,您可能希望在应用程序的工具栏上实现缩放命令,该命令仅导致当前活动项目被缩放,如下图所示。

为了支持这种情况,Prism提供了IActiveAware界面。该IActiveAware接口定义了一个IsActive返回属性true时实施者是活动的,并且IsActiveChanged当活动状态改变时引发事件。

您可以IActiveAware在视图或ViewModel上实现该接口。它主要用于跟踪视图的活动状态。视图是否处于活动状态由特定控件内的视图决定。例如,对于Tab控件,有一个适配器将当前选定选项卡中的视图设置为活动状态。

DelegateCommand类还实现了IActiveAware接口。CompositeCommand可被配置成评估子类DelegateCommands的活动状态(除了CanExecute通过指定状态)truemonitorCommandActivity在构造参数。当此参数设置为时trueCompositeCommand类在确定方法的返回值以及在CanExecute方法中执行子命令时将考虑每个子DelegateCommand的活动状态Execute

    public class ApplicationCommands : IApplicationCommands
{
private CompositeCommand _saveCommand = new CompositeCommand(true);
public CompositeCommand SaveCommand
{
get { return _saveCommand; }
}
}

monitorCommandActivity参数为时trueCompositeCommand该类表现出以下行为:

  • CanExecutetrue仅在可以执行所有活动命令时返回。根本不会考虑不活动的子命令。
  • Execute:执行所有活动命令。根本不会考虑不活动的子命令。

通过IActiveAware在ViewModel上实现界面,当您的视图变为活动或非活动时,您将收到通知。当视图的活动状态更改时,您可以更新子命令的活动状态。然后,当用户调用复合命令时,将调用活动子视图上的命令。

public class TabViewModel : BindableBase, IActiveAware
{
private bool _isActive;
public bool IsActive
{
get { return _isActive; }
set
{
_isActive = value;
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()
{
//implement logic
} private void OnIsActiveChanged()
{
UpdateCommand.IsActive = IsActive; //set the command as active
IsActiveChanged?.Invoke(this, new EventArgs()); //invoke the event for al listeners
}
}

Prism_Composite Commands(3)的更多相关文章

  1. useful commands for Kubernetes beginners

    Get pod ip and their coordinating NODE $ kubectl get pods -o wide If you want to get detailed inform ...

  2. useful commands for docker beginner

    You may want to add my wechat public account or add my technical blog's RSS feed This list is meant ...

  3. useful Ansible commands

    This article includes some useful Ansible commands. I will try to write blogs by English. You may wa ...

  4. The common Linux Commands

    Linux的命令总结 1. man:在线请求系统帮助 例:man mkdir NAME:这个命令的完整全名 mk(make directories) SYNOPSIS:这个命令的基本语法 mkdir ...

  5. The commands of Disk

    The commands of Disk fdisk( the disk size is less 2TB) fdisk - partition table manipulator for Linux ...

  6. Network Basic Commands Summary

    Network Basic Commands Summary set or modify hostname a)     temporary ways hostname NEW_HOSTNAME, b ...

  7. linux commands

    abrt-cli --since ;查看abrt捕捉的异常 alias ;别名,alias rm='rm -i':使用“ \rm ” 使用原命令 alsamixer ;图形音量调节,q 增加左声道, ...

  8. OWIN 中 K Commands 与 OwinHost.exe 相等吗?

    OwinHost.exe: While some will want to write a custom process to run Katana Web applications, many wo ...

  9. OWIN 中 K Commands(OwinHost.exe)与 Microsoft.AspNet.Hosting 的角色问题

    问题详情:K Commands(OwinHost.exe)是不是 OWIN 中的 Host 角色?如果是,那 Microsoft.AspNet.Hosting 对应的是 OWIN 中的哪个角色? OW ...

随机推荐

  1. golang数据结构之总结

    golang语言的一些数据结构实现,包括: 队列(单队列.循环队列) 链表(单链表.双链表.循环链表(解决约瑟夫环问题)) 栈(实现加减乘除计算) 递归之迷宫问题 哈希表(员工管理系统) 树(三种遍历 ...

  2. HTML <input> placeholder 属性

    css ::-webkit-input-placeholder { /* WebKit, Blink, Edge */ color: #909; } :-moz-placeholder { /* Mo ...

  3. CentOS7.2下PXE+kickstart自动化安装系统

    一.实验环境 操作系统:CentOS Linux release 7.2.1511 (Core) 网卡地址:192.168.100.147/24 光盘镜像:CentOS-7-x86_64-Minima ...

  4. Web基础了解版01-html-css

    HTML 网页构成 摘要 说明 结构(HTML) HTML是网页内容的载体.内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. 表现(CSS) CSS样式是表现.就像网页的 ...

  5. JS实现链式调用 a().b().c()

    function a() { this.b = function () { console.log('111') return this } this.c = function () { consol ...

  6. JS基础-变量类型和类型转换

    JS 变量类型 JS中有 6 种原始值,分别是: boolean number string undefined symbol null 引用类型: 对象 数组 函数 JS中使用typeof能得到哪些 ...

  7. 自动化运维之SaltStack实践

    自动化运维之SaltStack实践 1.1.环境 linux-node1(master服务端) 192.168.0.15 linux-node2(minion客户端) 192.168.0.16 1.2 ...

  8. 深入学习socket网络编程,以java语言为例

    了解java的socket编程与Linux Socket API之间的关系 一.java的网络编程 1.socket原理 socket通信就是通过IP和端口号将两台主机建立连接,提供通信.主机A的应用 ...

  9. Brett Beauregard大神的Arduino PID算法

    大神的全部PID http://brettbeauregard.com/blog/category/pid/ Improving the Beginner’s PID – Introduction I ...

  10. 《Java基础知识》Java 泛型详解

    JDK 1.5 之后,Java 通过泛型解决了容器类型安全这一问题,而几乎所有人接触泛型也是通过Java的容器.那么泛型究竟是什么? 泛型的本质是参数化类型:也就是说,泛型就是将所操作的数据类型作为参 ...