WPF Commend 命令

    WPF为我们准备了完善的命令系统,你可能会问:“有了路由事件为什么还需要命令系统呢?”。事件的作用是发布、传播一些消息,消息传达到了接收者,事件的指令也就算完成了,至于如何响应事件送来的消息事件并不做任何限制,每个接收者可已用自己的行为来响应事件。也就是说,事件不具有约束力。命令和事件的区别就在于命令具有约束力


1. WPF中命令的组成元素以及元素之间的关系


下面直接给出其组成元素:
•命令(Command)实现了ICommand接口的类,使用比较多的是RoutedCommand

•命令源(Command Source)命令的发送者,现实了ICommandSource接口的类,实现此类的元素主要有ButtonBase,Hyperlink,MenuItem、ListBoxItem等

•命令目标(Command Target)命令的接受者,实现了IInputElement接口的类。

•命令关联(Command Binding)负责把外围的逻辑与命令关联起来。


    相对事件的元素来说,命令元素之间的关系还是会复杂一些,具体的关系会通过命令的使用来说明。下面先简单介绍一下自定义命令的步骤。 


a、创建命令类
    如果命令没有涉及到业务逻辑的话,一般使用WPF类库的RoutedCommand类即可,如果要声明相对逻辑复杂一些的类,可以实现RouteCommand类的继承或者是ICommand的接口。

b、声明命令实例
    由于命令的普遍性,一般情况下程序中某类命令只需要一个命令实例即可(单件模式)。

c、指明命令的源
    通常是可以点击的控件,命令还有个好处就是,没有准备好的命令,这个控件不可用。如果把命令看做炮弹,那么命令源相当于火炮,这个火炮还是防走火的。

d、指明命令的目标
    目标是命令的作用对象。如果指定了目标,无论是否有焦点,都会受到这个命令。如果没有指定目标的话,拥有焦点的对象默认为命令目标。还有一个要注意的是设置目标是通过命名的源来设置的。格式为:命令源控件.CommandTarget = 目标控件;

e、设置命令关联
    关于设置命令关联还是在实例中好好的体会一下吧。下面就通过一个例子来说明。



2. 小试命令


下面的例子实现的是点击按钮时,清除文本框里面的内容。由于代码注释写的比较详细,直接给代码,然后具体再解释:

XAML:

<Window x:Class="WpfApplication9.wnd913"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="525">
    <StackPanel x:Name="_stackPanel" Background="LightSlateGray">
        <Button x:Name="_btnClear" Content="Clear" Height="28" Margin="5"/>
        <TextBox x:Name="_txtBox" Height="120"/>
    </StackPanel>
</Window>

C#:

    public partial class wnd913 : Window
    {
        /// <summary>
        /// 声明并定义命令
        /// </summary>
        private RoutedCommand _clearCmd = new RoutedCommand("clear", typeof(wnd913));

        public wnd913()
        {
            InitializeComponent();

            // 指定命令源与快捷键(输入笔势)
            _btnClear.Command = _clearCmd;
            _clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));

            // 指定命令目标
            _btnClear.CommandTarget = _txtBox;

            // 创建命令关联
            CommandBinding cb = new CommandBinding();
            cb.Command = _clearCmd;
            cb.CanExecute += cb_CanExecute;
            cb.Executed += cb_Executed;

            // 命令关联安置到外围控件上
            _stackPanel.CommandBindings.Add(cb);
        }

        void cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            _txtBox.Clear();

            // 执行完毕
            e.Handled = true;
        }

        void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if(string.IsNullOrEmpty(_txtBox.Text))
            {
                e.CanExecute = false;
            }
            else
            {
                e.CanExecute = true;
            }
        }
    }


第一,使用命令可以避免自己写代码判断Button是否可以用以及添加快捷键。


第二,RountedCommand是一个与业务逻辑无关的类,只负责在程序中跑腿而并不对命令目标进行操作,TextBox并不是由它清空的。那么TextBox的情况操作是谁呢?答案是CommandBinding。因为无论是探测命令是否可以执行还是命令送达目标,都会激发命令目标发送路由事件,这些事件会沿着UI元素树向上传递,最终被CommandBinding所捕捉。本例中CommandBinding被安装在外围的StackPanel上,Commandbinding站在高处起一个侦听器的作用,而且专门针对rouutedCommand命令捕捉与其相关的事件。本例中,当CommandBinding捕捉到CanExecute就会调用cb_CanExecute方法。当捕捉到是Executed的时候,就调用cb_Execute事件。


第三,因为CanExecute事件的激发频率比较高,为了避免降低性能,在处理完毕之后建议将e.Handle设置为true。


第四,CommandBinding一定要设置在命令目标的外围控件上,不然无法捕捉CanExecute和Executed等路由事件。


3. WPF命令库


    命令具有一处声明,处处使用的特点,比如Save命令,在程序的任何地方它都表示要求命令目标保存数据。因此,微软在WPF类库里面准备了一些便捷的命令库,这些命令库包括:


ApplicationCommands
ComponentCommands
NavigationCommands
MediaCommands
EditingCommands


    它们都是静态类,而命令就是由这些静态类的只读属性以单件模式暴露出来的。例如:ApplicationCommands类就包含CancelPrint、Close、ContextMenu、Copy、CorrectionList、Cut、Delete、Find、Help、New、NotACommand、Open、Paste、Print、PrintPreview、Properties、Redo、Replace、Save、SaveAs、SelectAll、Stop、Undo这些命令。


    这就引起了一个问题:如果界面上有两个按钮一个用来创建Student档案,一个用来创建Teacher档案。都使用New命令的话,程序应该如何区别新建的是什么档案呢?


    答案是使用CommandParameter,命令源一定是实现了ICommandSource接口的对象,而ICommandSource有一个属性就是CommandParameter,如果把命令看作飞向目标的炮弹,那么CommandParameter就相当于装载在炮弹里面的“消息”。下面是程序的实现代码。


XAML:

<Window x:Class="WpfApplication9.wnd914"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="wnd914" Height="219.231" Width="300">
    <StackPanel x:Name="_stackPanel" Margin="5">
        <TextBox x:Name="_txtBox" Margin="5"/>
        <Button x:Name="_btn1" Content="Teacher" Margin="5"/>
        <Button x:Name="_btn2" Content="Student" Margin="5"/>
        <ListBox x:Name="_listBox" Height="70" Margin="5"/>
    </StackPanel>
</Window>

C#:

    public partial class wnd914 : Window
    {
        public wnd914()
        {
            InitializeComponent();

            _btn1.Command = ApplicationCommands.New;
            _btn1.CommandParameter = "Teacher";

            _btn2.Command = ApplicationCommands.New;
            _btn2.CommandParameter = "Student";

            CommandBinding cb = new CommandBinding();
            cb.Command = ApplicationCommands.New;
            cb.CanExecute += cb_CanExecute;
            cb.Executed += cb_Executed;
            _stackPanel.CommandBindings.Add(cb);
        }

        void cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            _listBox.Items.Add(e.Parameter.ToString());
        }

        void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(_txtBox.Text))
            {
                e.CanExecute = false;
            }
            else
                e.CanExecute = true;
        }
    }


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郎涯技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值