• 8.WPF命令


    8.WPF命令

    命令系统的基本元素

    • 命令:实现了ICommand的类,常见的是RoutedCommand类,也可以自定义命令
    • 命令源:命令的发送者,要实现ICommandSource接口
    • 命令目标:命令发送给谁,或者说命令作用在谁身上,必须实现IInputElement接口
    • 命令关联:把一些外围逻辑和命令关联起来,如之前判断是否可执行,以及命令执行之后还要执行哪些工作

    命令的基本使用步骤

    1. 创建命令类,实现ICommand接口,如果命令与具体逻辑无关,则直接可以使用RoutedCommand类。

    2. 声明命令实例,一般一个程序某种操作只需要一个命令实例(命令目标可设置多个)。

    3. 指定命令源,指定谁发送命令,如保存命令可以通过菜单栏来发送,也可以通过快捷工具栏来发送。同时命令源会受命令的影响,如命令不能被执行时,命令源控件为不可用状态。

    4. 指定命令目标,命令目标不是命令的属性,而是命令源的属性。如果没有为命令源设置命令目标,则当前拥有焦点的对象为命令目标。

    5. 设置命令关联,通过CommandBinding在执行前帮助判断命令是否可执行,并在执行后处理其他逻辑。

      **命令目标和命令关联之间的关系:**当命令源和命令目标建立联系后,命令目标会不停发送可路由的PreviewCanExecute和CanExecute事件,事件会沿着UI元素树传递最后被命令关联所捕获,命令关联捕获到这些事件后,把命令能不能执行报告给命令。类似的,如果命令被发送出来并送达目标命令,命令目标会发送PreviewExecuted和Executed事件,这两个事件也会被命令关联捕获,然后命令关联去执行后续工作。其中,命令目标负责发送各种事件,命令负责跑腿,真正执行操作的是命令关联。

    使用命令的好处:可以避免自己写代码判断控件是否可用以及添加快捷键

    案例:

    <StackPanel x:Name="stackPanel">
        <Button x:Name="btn" Content="Send Command" Margin="5"/>
        <TextBox x:Name="txtA" Height="100" Margin="5,0"/>
    StackPanel>
    
    • 1
    • 2
    • 3
    • 4

    后台代码

    public MainWindow()
    {
        InitializeComponent();
        InitializeCommand();
    }
    //声明并定义命令
    private RoutedCommand clearCmd = new RoutedCommand("Clear", typeof(MainWindow));
    private void InitializeCommand()
    {
        //把命令赋值给命令源
        this.btn.Command = this.clearCmd;
        this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));//给命令设置快捷键
    
        //指定命令目标
        this.btn.CommandTarget = this.txtA;//这是目标源的属性
    
        //创建命令关联
        CommandBinding cb = new CommandBinding();
        cb.Command = this.clearCmd; //只关注与clearCmd相关的事件
        cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
        cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
    
        //把命令关联安置在外围控件上
        this.stackPanel.CommandBindings.Add(cb);
    
    }
    //命令送达目标后,此方法被调用
    private void cb_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        this.txtA.Clear();
        e.Handled = true;//避免继续传递而降低性能
    }
    //判断命令是否可执行
    private void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        if (string.IsNullOrEmpty(this.txtA.Text))
        {
            e.CanExecute = false;
        }
        else
        {
            e.CanExecute = true;
        }
        e.Handled = true;//避免继续传递而降低性能
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOAzbx8r-1667881224116)(8.WPF命令.assets/image-20221108102114461.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yRszzED7-1667881224117)(8.WPF命令.assets/image-20221108102127153.png)]

    ​ *案例说明:*RoutedCommand是一个与业务逻辑无关的类,只负责在程序中“跑腿”,而不会对命令目标执行任何操作。命令关联把命令能否可用告诉命令,然后会影响到命令源。命令到达命令目标后,命令目标会触发相关事件。

    真正对命令目标执行操作的是命令关联。

    命令目标不断的发送路由事件,CommandBinding需要安装在外围的UI树上,起到一个监听作用。

    因为命令目标会不断发送CanExecute事件,为了避免降低性能,建议处理完后把e.Handled设置为True。

    WPF命令库和命令参数

    WPF类库中已经准备了常用的命令如打开、关闭、撤销等。这些命令库包括

    • ApplicationCommands
    • ComponentCommands
    • NavigationCommands
    • MediaCommands
    • EditingCommands

    这些都是静态类,其中的命令则是类中的静态属性。

    命令参数

    命令库中的静态预制命令,全局仅有一个,而如果界面有两个按钮,分别需要用New命令新建不同的工程,如何实现?

    命令源实现了ICommandSource接口,接口中具有CommandPrameter属性,表示命令的相关信息。

    <Grid Margin="6">
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="24"/>
            <RowDefinition Height="4"/>
            <RowDefinition Height="*"/>
        Grid.RowDefinitions>
        <TextBlock Text="Name:" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="0"/>
        <TextBox x:Name="txtName" Margin="60,0,0,0" Grid.Row="0"/>
        <Button Content="New Teacher" Command="New" CommandParameter="Teacher" Grid.Row="2"/>
        <Button Content="New Student" Command="New" CommandParameter="Student" Grid.Row="4"/>
        <ListBox x:Name="list" Grid.Row="6"/>
    Grid>
    <Window.CommandBindings>
        <CommandBinding Command="New" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/>
    Window.CommandBindings>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        if (string.IsNullOrEmpty(this.txtName.Text))
        {
            e.CanExecute = false;
        }
        else
        {
            e.CanExecute = true;
        }
        e.Handled = true;
    }
    
    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        string name = this.txtName.Text;
        if (e.Parameter.ToString()=="Teacher")
        {
            this.list.Items.Add($"新教师{name}");
        }
        if (e.Parameter.ToString() == "Student")
        {
            this.list.Items.Add($"新学生{name}");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfDhOShs-1667881224118)(8.WPF命令.assets/image-20221108110215928.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-toMxNSiN-1667881224118)(8.WPF命令.assets/image-20221108110230362.png)]

    命令与Binding的结合

    控件只有一个Command属性,而命令库有数十种命令,如何使用唯一的Command属性来调用多个命令,答案是Binding。

    例如,一个button所关联的命令可能根据某些条件而改变

  • 相关阅读:
    Glide原理
    过滤器和拦截器的基本知识
    非零基础自学Java (老师:韩顺平) 第15章 泛型 15.1 && 15.2 泛型的理解和好处
    Verilog写状态机的三种描述方式之三段式
    港联证券:市场有望从2024年起进入大众化折叠屏手机时代
    (1)安装hadoop之虚拟机准备(配置IP与主机名)
    cefshar117.2.40(cef117.2.4)Chromium 117.0.5938.150小更新
    2022数学建模国赛降至,整理了一些很不错的在线网站分享一下
    【STM32】通用定时工作原理
    textarea 让多行输入框 高度随内容变化
  • 原文地址:https://blog.csdn.net/weixin_44064908/article/details/127748397