深入浅出WPF-09.Command(命令)
命令
1)命令系统的基本元素
- 命令(Command),WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类
 - 命令源(Command Source),即命令的发出者,是实现了ICommandSource接口的类,很多界面元素都实现了这个接口,比如Button,MenuItem,ListBoxItem等等
 - 命令目标(Command Target),即命令将发送给谁,或者说命令将作用在谁的身上。实现了IInputElement接口的类。
 - 命令关联(Command Binding),负责把一些外围逻辑和命令关联起来,比如执行前对命令判断是否可以执行进行判断,命令执行后还要做哪些后续工作
 
2)基本元素之间的关系
基本元素之间的关系体现在使用命令的过程中,命令的使用大致分为5个步骤:
1)创建命令类:即获取一个实现ICommand接口的类,如果命令与具体的业务逻辑无关,则使用WPF类库中的RoutedCommand类即可。如果想得到与业务逻辑相关的专有命令,则需要创建RoutedCommand或者ICommand的派生类。
2)声明命令实例:使用命令时需要创建命令类的实例。这里有个技巧,一般情况下程序中某种操作只需要一个命令实例与之对应即可。比如保存命令,可以拿同一个实例去命令每个组件执行其保存功能,因此程序中的命令多使用单例模式,减少代码的复杂度
3)指定命令的源:指定由谁来发送这个命令。同一个命令可以有多个源。一旦把命令指派给命令源,那么命令源就会受命令的影响,当命令不能被执行的时候,命令源控件将处于不可用状态。
4)指定命令目标:命令目标并不是命令的属性,而是命令源的属性,指定命令目标是告诉命令源向哪个组件发送命令,无论这个组件是否拥有焦点他都会收到这个命令。如果没有为命令源指定命令目标,则WPF系统认为当前焦点的对象就是命令目标。
5)设置命令关联:WPF命令需要CommandBinding在执行前来帮助判断是不是可以执行,执行后做一些处理工作。
在命令目标和命令关联之间有一种微妙的关系,无论命令目标是由程序员指定还是WPF根据焦点判断出来的,一旦某个UI组件被命令源盯上,命令源就会不停的向命令目标投石问路,命令目标就不停地发送路由事件PreviewCanExecute和CanExecute,事件会沿着UI元素树向上传递并被命令关联所捕获,命令关联捕获到这些事件后,会把命令能不能发送实时的告诉给命令。如果命令发送出来并到达命令目标,命令目标就会发送PreviewExecuted和Executed路由事件,这两个事件沿着UI元素树向上传递并被命令关联捕捉,命令关联会完成一些后续的任务。所以这个过程一共会产生4个事件。

demo:
<Window x:Class="CommandDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="Auto" Width="Auto" SizeToContent="WidthAndHeight">
    <Grid>
        <StackPanel Width="300" Name="stackPanel">
            <Button x:Name="button1" Margin="5" Content="Send Command"/>
            <TextBox x:Name="txtbox1" Margin="5" Height="100"/>
        </StackPanel>
    </Grid>
</Window>
public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //把命令赋值给命令源(发送者)并指定快捷键
            this.button1.Command = ClearCmd;
            this.ClearCmd.InputGestures.Add(new KeyGesture(Key.C,ModifierKeys.Alt));
            //指定命令的目标
            this.button1.CommandTarget = this.txtbox1;
            //创建命令关联
            CommandBinding cb = new CommandBinding();
            cb.Command = this.ClearCmd;
            cb.CanExecute += Cb_CanExecute;
            cb.Executed += Cb_Executed;
            //把命令关联在外围控件上
            this.stackPanel.CommandBindings.Add(cb);
        }
        private void Cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.txtbox1.Clear();
            //避免继续向上传递而降低性能
            e.Handled = true;
        }
        private void Cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if(string.IsNullOrEmpty(this.txtbox1.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
            //避免继续向上传递而降低性能
            e.Handled = true;
        }
        // 声明并定义命令
        private RoutedCommand ClearCmd = new RoutedCommand("Clear", typeof(MainWindow));
    }
以上demo的几点说明:
1)使用命令可以避免自己写代码判断Button是否可用以及添加快捷键
2)RoutedCommand是一个与业务逻辑无关的类,只负责在程序中跑腿,而并不对命令目标做任何操作。TextBox并不是由他清空的,而是CommandBinding。无论是探测命令是否可以执行还是命令送达目标,都会激发命令目标发送路由事件,这些路由事件会沿着UI元素树向上传递并最终被CommandBinding捕获。本例中,将CommandBinding安装在外围的StackPanel上,CommandBinding站在高处起到一个侦听器的作用,而且专门针对ClearCmd命令捕获与其相关的路由事件。当CommandBinding捕捉到CanExecute事件就会调用Cb_Executed方法(判断命令是否可以执行,并反馈给命令供其影响命令源的状态);当捕捉到Executed事件(表示命令已经执行了,或者说命令已经作用在命令目标上了。RoutedCommand的Executed方法不包含业务逻辑,只负责让命令目标激发Executed),则调用Cb_Executed方法
3)因为CanExecute事件激发的频率比较高,为了避免降低性能,在处理完之后建议把e.Handled = true;
4)CommandBindings一定设置在命令目标的外围控件中,否则无法捕获到CanExecute和Executed等路由事件
前面提到了命令可以是单例的,那么同样的命令如何区分呢?那就通过命令参数CommandPrameter。在CanExecute和Executed等路由事件中,可以通过这个命令参数进行区分。
控件有很多事件,可控件只有一个Command属性,而命令库中有很多命令,怎么才能确定调用哪个命令呢?使用Binding,通过Binding赋值,来设置控件的命令属性。
深入浅出WPF-09.Command(命令)的更多相关文章
- 《深入浅出WPF》笔记——事件篇
		
如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...
 - Windows Presentation Foundation (WPF)中的命令(Commands)简述
		
原文:Windows Presentation Foundation (WPF)中的命令(Commands)简述 ------------------------------------------- ...
 - 【转】【WPF】WPF 自定义快捷键命令(Command)
		
命令简介 WPF 中的命令是通过实现 ICommand 接口创建的.ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged).Exec ...
 - WPF自学入门(十一)WPF MVVM模式Command命令
		
在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正如上一篇文章中在开始说的,MVVM的目的是为了最大限度地降低了 ...
 - WPF 自定义快捷键命令(COMMAND)(转)
		
命令简介 WPF 中的命令是通过实现 ICommand 接口创建的.ICommand 公开两个方法(Execute 及 CanExecute)和一个事件(CanExecuteChanged).Exec ...
 - WPF自学入门(十一)WPF MVVM模式Command命令        WPF自学入门(十)WPF MVVM简单介绍
		
WPF自学入门(十一)WPF MVVM模式Command命令 在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式 ...
 - WPF中的命令(Command)
		
这节来讲一下WPF中的命令(Command)的使用. [认识Command] 我们之前说过,WPF本身就为我们提供了一个基础的MVVM框架,本节要讲的命令就是其中一环,通过在ViewModel中声明命 ...
 - 《深入浅出WPF》 学习笔记
		
<深入浅出WPF> 序言 1. 什么是WPF 2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...
 - 16、WPF中的命令
		
一.前言 事件的作用是发布.传播一些信息,消息送达接收者,事件的使命就算完成了,至于如何响应事件送来的消息事件并不做规定,每个接收者可以使用自己的行为来响应事件,也就是说事件不具有约束力.命令能够在代 ...
 - 【【分享】深入浅出WPF全系列教程及源码
】
		
因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...
 
随机推荐
- 如何修改leaflet的marker图标
			
1. 从官网中查看对应文档:https://leafletjs.com/ 2. 3. var greenIcon = L.icon({ iconUrl: 'leaf-green.png', shado ...
 - 面试题:hashcode相等两个类一定相等吗?equals呢?相反呢?
			
首先如果hashcode相等的话,这两个类也是不一定相等的,如果是反过来的话(通常情况下,如果两个对象的内容相同,两个对象的hashcode也是相同的) hashcode()和equals()的关系: ...
 - Spring详解(九)------事务管理
			
1.事务介绍 事务(Transaction),一般是指要做的或所做的事情.在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit). 这里我们以取钱的例子来讲解:比如你去ATM ...
 - 【springcloud】一文带你搞懂API网关
			
作者:aCoder2013 https://github.com/aCoder2013/blog/issues/35 前言 假设你正在开发一个电商网站,那么这里会涉及到很多后端的微服务,比如会员.商品 ...
 - ubuntu黑屏无法进入系统【Recovery Mode急救】
			
一.问题 前言:因为一次美化配置ubuntu导致系统启动黑屏,无法进入系统.之前并没有系统备份,后果严重还好修复了,记录下修复步骤备用. 事件:就是因为修改了 /usr/share/gnome-sh ...
 - 带有附件及图片正文的JavaMail邮件发送
			
1 package javamail; 2 3 import java.io.UnsupportedEncodingException; 4 import java.util.Properties; ...
 - mybaits源码分析(一)
			
一.源码下载 1.手动编译源码 为了方便在看源码的过程中能够方便的添加注释,可以从官网下载源码编译生成对应的Jar包,然后上传到本地maven仓库,再引用这个Jar. 首先需要编译打包parent项目 ...
 - spring-data-redis 动态切换数据源
			
最近遇到了一个麻烦的需求,我们需要一个微服务应用同时访问两个不同的 Redis 集群.一般我们不会这么使用 Redis,但是这两个 Redis 本来是不同业务集群,现在需要一个微服务同时访问. 其实我 ...
 - JavaScript 特殊字符
			
代码输出\'单引号\"双引号\&和号\\反斜杠\n换行符\r回车符\t制表符\b退格符\f换页符
 - Why TypeScript?
			
本文经作者授权,翻译总结自 TypeScript Team 的成员 orta 的个人博客 <Understanding TypeScript's Popularity>. 原作者: ort ...