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实例,然后将其公开为ICommand或ComponsiteCommand属性。

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通过指定状态)true为monitorCommandActivity在构造参数。当此参数设置为时true,CompositeCommand类在确定方法的返回值以及在CanExecute方法中执行子命令时将考虑每个子DelegateCommand的活动状态Execute。

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

当monitorCommandActivity参数为时true,CompositeCommand该类表现出以下行为:

  • CanExecute:true仅在可以执行所有活动命令时返回。根本不会考虑不活动的子命令。
  • 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. 云享专家倪升武:微服务架构盛行的时代,你需要了解点 Spring Boot

    [摘要] 微服务架构的本质在于分布式.去中心化. 随着互联网的高速发展,庞大的用户群体和快速的需求变化已经成为了传统架构的痛点. 在这种情况下,如何从系统架构的角度出发,构建出灵活.易扩展的系统来快速 ...

  2. 让微信推送Jenkins构建消息

    Jenkins作为开发必备之神器,各家大小公司都在使用.Jenkins自身内置了基于邮件推送构建结果的功能.但是随着移动互联网的发展,邮件这玩意已经越来越少使用了,是否有一种办法能把jenkins构建 ...

  3. MySQL的存储(二、创建表并插入)

    创建表 首先创建一个 spiders的数据库 cursor.execute("create database spiders default character set utf8" ...

  4. [TimLinux] JavaScript 代码控制滚动条移动到顶部/底部

    1. scrollIntoView函数 这个函数控制滚动条顶部内容.还是底部内容呈现在视图窗口中,接收一个参数:boolean值. true: 顶部出现在视图窗口中 false: 底部存在在视图窗口中 ...

  5. 2017 CCPC秦皇岛 E题 String of CCPC

    BaoBao has just found a string  of length  consisting of 'C' and 'P' in his pocket. As a big fan of ...

  6. 小程序 - 解决IOS端使用css滤镜渲染出现异常

    在页面渲染时,GPU默认不会开启.当css样式中出现某些规则时,就会开启GPU加速,让动画运行的更加流畅,最显著的象征就是元素的3D变换. 这些就是我们通常所说的css硬件加速,但我们有时候并不需要用 ...

  7. wow钓鱼方案

    最近怀旧服启动了 玩(排)得我萎靡不堪 突然想起多年前写过一个钓鱼的按键精灵 赶紧搜出来助我一臂之力 奈何往年不知其珍贵 早不见了 千思万想才在群空间的文件夹内翻出来一个exe版本 而源代码已不知去向 ...

  8. java的传参究竟是按值传递的还是按引用传递的

    这里来弄清楚Java的传参究竟是按值传递的还是按引用传递的. 形参和实参 传参的概念里,有形参和实参的区分.形参是定义方法名和方法体的时候使用的参数,目的是用来接收调用该方法的时候传入的参数:实参是调 ...

  9. tensorflow tf.train.Supervisor作用

    tf.train.Supervisor可以简化编程,避免显示地实现restore操作.通过一个例子看. import tensorflow as tf import numpy as np impor ...

  10. 笔记||Python3之字符串格式化输出

    字符串的格式化输出方法一: 常用的字符串格式化符号:%s   ---   用str()函数进行字符串转换 %d   ---   转成有符号十进制数 %f    ---   转成浮点数(小数部分自然截断 ...