zoukankan      html  css  js  c++  java
  • 深入浅出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赋值,来设置控件的命令属性。

  • 相关阅读:
    WinForm获取窗体关闭原因和是否取消关闭值
    DIV CSS 居中代码(以及靠右)
    C#获取本机所有IP地址(包括局域网和本机外网IP)
    C# WinForm关闭窗体确认
    .NET WinForm全屏和退出以及蓝屏黑屏等
    HTML5标签
    C# 文件、文件夹操作语句(删除,创建,移动,检查是否存在)
    jquery聚焦文本框
    JS当前页面登录注册框,固定DIV,底层阴影
    Visual Studio 怎样添加引用
  • 原文地址:https://www.cnblogs.com/vigorous/p/13396618.html
Copyright © 2011-2022 走看看