• WPF之命令


      命令与事件类似,事件用来发布传播一些消息,消息到达接收者,事件的使命就完成了,至于如何响应事件送来的消息事件并不做规定;而命令一旦发出,所有的命令目标都必须执行这个命令,二者的区别就在命令具有约束力而事件没有。

      命令的基本元素

    • 命令(Command):WPF的命令实际就是实现了ICommand接口的类,平时使用最多的是RotuedCommand类;
    • 命令源(Command Source):命令发送者,是实现类ICommandSource接口的类,例如Button、MenuItem、ListBoxItem等;
    • 命令目标(Command Target):命令将作用在谁身上,命令目标必须实现了IInputElement接口;
    • 命令关联(Command Binding):负责把一些外围逻辑与命令关联起来,比如执行前对命令是否可以执行进行判断、命令执行之后进行一些后续工作等。

      命令的使用步骤

    1. 创建命令类:获得一个实现了ICommand的类,如果命令与具体的业务逻辑无关,可以使用WPF类库的RotuedCommand;
    2. 声明命令实例:创建命令类的实例。一般情况下,程序中的某种操作只需要一个命令实例与之对应即可,比如“保存”命令,可以拿同一个实例去命令所有组件完成保存功能,因此命令常使用单例模式;
    3. 指明命令源:指定由谁来发送这个命令。同一个命令可以有多个命令源,如保存命令,可以由菜单中的保存项发送,也可以由工具栏的保存图标发送;
    4. 指定命令目标:命令目标并不是命令的属性而是命令源的属性,指定命令目标是告诉命令源向哪个组件发送命令,无论这个组件是否获得焦点它都会收到这个命令。如果没有为命令源指定目标,则WPF系统认为当前拥有焦点的对象就是命令目标;
    5. 设置命令关联:指定命令针对用户界面的具体区域,可以添加到命令源的外围控件上。

      一个UI组件一旦被命令源盯上,命令源就会不停地向命令目标“投石问路”,命令目标也会不停地发送出可路由的CanExcute附加事件,事件沿着UI元素树向上传递并被命令关联捕捉,命令关联捕捉到这些事件后会把命令能不能发送实时报告给命令。

      如果命令被发送出去并到达命令目标,命令目标就会发送Excute附加事件,事件沿着UI元素树向上传递并被命令关联捕捉,命令关联会完成指定的后续任务。 

      现在我们实现这样一个需求,定义一个命令,使用Button来发送这个命令,当命令到达TextBox时,TextBox的文本会被清空,如果TextBox文本为空则命令不可发送,XAML代码如下:

    <Window x:Class="WpfApplication7.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel x:Name="stackpanel">
            <TextBox x:Name="textBox1" Height="23" Margin="10"></TextBox>
            <Button x:Name="button1" Content="发送命令" Height="23" Margin="10"></Button>
        </StackPanel>
    </Window>

      后台处理代码如下:

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                InitCmd();
            }
    
            private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(MainWindow));
            
            private void InitCmd()
            {
                //指定命令源、绑定快捷键
                this.button1.Command = clearCmd;
                this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
    
                //指定命令目标
                this.button1.CommandTarget = textBox1;
    
                //创建命令关联
                CommandBinding cb = new CommandBinding();
                cb.Command = this.clearCmd;
                cb.Executed += cb_Executed;
                cb.CanExecute += cb_CanExecute;
    
                //把命令关联安置到外围控件
                this.stackpanel.CommandBindings.Add(cb);
            }
    
            void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
            {
                if (string.IsNullOrEmpty(this.textBox1.Text))
                    e.CanExecute = false;
                else
                    e.CanExecute = true;
                //避免继续向上传而降低程序性能
                e.Handled = true;
            }
    
            void cb_Executed(object sender, ExecutedRoutedEventArgs e)
            {
                this.textBox1.Clear();
                e.Handled = true;
            }
        }

      可见,使用命令就不需要自己写代码判断Button是否可用,CanExcute事件触发频率比较高,为了避免降低性能,在处理完后需要把e.handled设置为ture;CommandBinding一定要设置在命令目标的外围控件上,不然无法捕捉到CanExcute和Excute事件。

      命令参数

      WPF有很多命令,如New、Copy等,如果界面上有两个Button,一个用来New一个Teacher档案,一个用来New一个Student档案,该如何解决呢?这时就用到了命令的CommandPrameter属性。

      我们使用WPF系统的预置命令New,XAML代码如下:

    <Window x:Class="WpfApplication7.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel x:Name="stackpanel">
             <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Name" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left"></TextBlock>
                <TextBox x:Name="textBox2" Grid.Column="1" Height="23" Margin="5"></TextBox>
            </Grid>
            <Button x:Name="btnTeacher" Content="Teacher" Command="New" CommandParameter="Teacher" Height="23" Margin="10"></Button>
            <Button x:Name="btnStudent" Content="Student" Command="New" CommandParameter="Student" Height="23" Margin="10"></Button>
        </StackPanel>
        <Window.CommandBindings>
            <CommandBinding Command="New" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"></CommandBinding>
        </Window.CommandBindings>
    </Window>

      CommandBinding的事件处理代码如下:

    private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
            {
                if (string.IsNullOrEmpty(this.textBox2.Text))
                    e.CanExecute = false;
                else
                    e.CanExecute = true;
                e.Handled = true;
            }
    
            private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
            {
                string name = this.textBox2.Text;
                if(e.Parameter.ToString()=="Teacher")
                {
                    this.textBox2.Text = "Hello Teacher";
                }
                if (e.Parameter.ToString() == "Student")
                    this.textBox2.Text = "Hello Student";
            }

      两个按钮都使用New命令,但分别使用Teacher和Student作为参数,当TextBox的Text为空时,Button不可用,当输入文本后Button变为可用,单击Button,TextBox会显示不同的内容。

      

  • 相关阅读:
    在VisualStudio2013,2015中如何安装自定义项目模板
    获取assemblies信息in .net core
    Entity Framework Code Migration 新建、更新数据库
    TFS命令tf:undo(强制签入签出文件)
    教你在Android手机上使用全局代理
    双因素认证(2FA)教程
    ubuntu 禁用 guest 账户
    ffmpeg综合应用示例(三)——安卓手机摄像头编码
    linux 查看cpu的使用百分比
    加密货币 (Cryptocurrency) 市值 (market capitalization) 列表
  • 原文地址:https://www.cnblogs.com/yijiaoyingbi/p/4881916.html
Copyright © 2020-2023  润新知