命令(ICommand)基础

命令可以看做事件的进化版,使用命令,可以使代码结构更清晰;还能更好的控制各个UI的状态(启用/禁用)。

1.命令四要素

  • 命令(Command):WPF的命令实际上是实现了ICommand接口的类,平常最多使用的是RoutedCommand类。
  • 命令源(Command Source):命令的发送者,是实现了ICommandSource接口的类。很多界面元素(如Button、MenuItem等)都实现了这个接口。
  • 命令目标(Command Target):命令将作用的目标,该目标必须实现IInputElement接口的类。
  • 命令关联(Command Binding):负责把一些外围逻辑与命令关联起来,比如执行之前对命令是否可以执行进行判断、命令执行之后还有哪些后续工作等。

2.使用命令

1)创建命令类:即获得一个实现ICommand接口的类。
2)声明命令实例:创建命令类的实例。
3)指定命令的源:指定命令的发送者。
4)指定命令目标:告诉命令源向哪个组件发送命令,如没有指定命令目标,WPF系统认为当前拥有焦点的对象为命令目标。
5)设置命令关联:WPF命令需要CommandBinding在执行前来帮助判断是不是可以执行、在执行后处理什么任务。

3.系统命令

系统命令包含5组:
  • ApplicationCommands提供一组标准的与应用程序相关的命令,包含Open、Close、Delete、Cut等。
  • ComponentCommands提供一组标准的与组件相关的命令,这些命令具有预定义的按键输入笔势和 RoutedUICommand.Text 属性。包含MoveLeft、MoveRight、MoveUp等。
  • NavigationCommands提供一组标准的与导航相关的命令,包括BrowseHome、BrowseStop、BrowseStop等。
  • MediaCommands提供一组标准的与媒体相关的命令,包括Play、Pause、Stop等。
  • EditingCommands提供一组标准的与编辑相关的命令,包括AlignCenter、Backspace、Delete等。
命令库中的命令仅表示 RoutedCommand 的实例,而不表示命令的实现逻辑。 实现逻辑通过 CommandBinding 绑定到命令。
很多控件都为命令库中的许多命令提供实现逻辑。 例如,TextBox 为 Paste、Cut、Copy、Undo 和 Redo 命令提供逻辑。
如下代码:(详细的截图说明可参见经验: WPF之Command基础:[2]系统命令)
xaml代码:
        <TabItem Header="系统命令">
            <Grid>
                <StackPanel Orientation="Horizontal" Margin="71,117,65,130">
                    <Button Command="Cut" CommandTarget="{Binding ElementName=textBox}"
                            Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
                    <Button Command="Copy" CommandTarget="{Binding ElementName=textBox}"
                            Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
                    <Button Command="Paste" CommandTarget="{Binding ElementName=textBox}"
                            Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
                    <Button Command="Undo" CommandTarget="{Binding ElementName=textBox}"
                            Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
                    <Button Command="Redo" CommandTarget="{Binding ElementName=textBox}"
                            Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
                    <TextBox x:Name="textBox" Width="200"/>
                </StackPanel>
                <Button HorizontalAlignment="Left" Height="37" Margin="113,235,0,0" 
                        VerticalAlignment="Top" Width="262"
                        Command="Close"
                        CommandTarget="{Binding ElementName=mainWindow}"
                        Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"/>
            </Grid>
        </TabItem>
cs代码:
            CommandBinding cbClose = new CommandBinding(ApplicationCommands.Close);
            cbClose.CanExecute += cbClose_CanExecute;
            cbClose.Executed += cbClose_Executed;
            this.CommandBindings.Add(cbClose);

...

        /// <summary>
        /// 关闭命令执行逻辑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cbClose_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 关闭命令是否可执行,这里直接返回true
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void cbClose_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

4.命令参数CommandParameter

通过命令参数,可以使用相同的命令来处理不同的任务,譬如不同的按钮使用相同的命令,但是命令参数不一样便可区分由哪个按钮触发。
(具体说明参见经验: WPF之Command基础:[3]命令参数)
下面的例子通过命令参数将文本框的值传递给命令进行处理,同时根据命令参数来判断命令是否可执行,具体代码如下:
XAML代码:
        <TabItem Header="命令参数">
            <Grid>
                <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="39" Margin="55,38,0,0" 
                         TextWrapping="Wrap" Text="TextBox1" VerticalAlignment="Top" Width="136"/>
                <Button x:Name="btnText1" Content="SayText1" HorizontalAlignment="Left" Height="45" Margin="55,116,0,0" 
                        VerticalAlignment="Top" Width="136"
                        CommandParameter="{Binding Path=Text,ElementName=textBox1}"/>
            </Grid>
        </TabItem>
CS代码:
        //声明并定义命令
        private RoutedCommand sayCmd = new RoutedCommand("Say", typeof(MainWindow));

...

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

...

            btnText1.Command = sayCmd;

...

        private void cb_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            string strMsg = "";
            strMsg += e.OriginalSource.GetType().Name;
            if (e.OriginalSource is TextBox)
            {
                strMsg += ":" + ((TextBox)e.OriginalSource).Text;
            }
            if (e.Parameter != null)
            {
                strMsg += "\r\nParameter=" + e.Parameter.ToString();
            }
            //执行命令
            MessageBox.Show(strMsg);
        }

        private void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (e.Parameter != null && e.Parameter.ToString() == "Param")
            {
                e.CanExecute = false;
            }
            else if (e.OriginalSource is TextBox)
            {
                //当文本框存在文本时可执行命令
                e.CanExecute = ((TextBox)e.OriginalSource).Text.ToString() == "" ? false : true;
            }
            else
            {
                e.CanExecute = true;
            }

            e.Handled = true;
        }

5.自定义命令

从ICommand接口开始,实现一个自定义命令。该自定义命令不再需要CommandBindings来进行命令绑定,在命令里面实现了相关的业务处理,使代码更清晰。
(具体可参见经验: WPF之Command基础:[4]自定义命令)
下面用自定义命令来实现上面的SayCommand命令。测试代码如下:
XAML代码:
        <TabItem Header="自定义命令">
            <Canvas>
                <local:MyLabel x:Name="mylabel" Content="命令测试" Height="54" Canvas.Left="114" Canvas.Top="165" Width="148"
                               Background="Gray"/>
                <TextBox x:Name="mytext" Height="73" Canvas.Left="114" TextWrapping="Wrap" Text="TextBox" Canvas.Top="42" Width="148"/>
            </Canvas>
        </TabItem>
自定义命令SayCommand代码如下:
    public class SayCommand : ICommand
    {
        //命令可执行逻辑
        public bool CanExecute(object parameter)
        {
            return false;
        }
        
        //命令的可执行状态更改时,激发此事件
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        //命令执行
        public void Execute(object parameter)
        {
            MessageBox.Show(((TextBox)parameter).Text);
        }
    }
CS代码:
        private void InitCommand1()
        {
            SayCommand sayCommand=new SayCommand();
            this.mylabel.Command = sayCommand;
            this.mylabel.CommandTarget = this.mytext;
        }

6.命令绑定

命令绑定通过Binding将命令绑定到Command上,也能绑定CommandParameter和CommandTarget。
(具体可参见经验: WPF之Command基础:[5]命令绑定)
下面将根据上篇自定义命令进行相应的更改,实现命令的绑定。代码如下:
自定义命令SayCommand2代码:
    public class SayCommand2 : ICommand
    {
        //命令可执行逻辑
        public bool CanExecute(object parameter)
        {
            return parameter.ToString().Length > 0;
        }

        //命令的可执行状态更改时,激发此事件
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        //命令执行
        public void Execute(object parameter)
        {
            MessageBox.Show(parameter.ToString());
        }
    }
测试XAML代码:
        <TabItem Header="命令绑定">
            <Canvas>
                <local:MyLabel2 Content="命令测试" Height="54" Canvas.Left="114" Canvas.Top="165" Width="148"
                                Background="Gray"
                                Command="{Binding SayCommand2}"
                                CommandParameter="{Binding Text,ElementName=box1}"/>
                <TextBox x:Name="box1" Height="73" Canvas.Left="114" TextWrapping="Wrap" Text="TextBox" Canvas.Top="42" Width="148"/>
            </Canvas>
        </TabItem>
测试CS代码:
        public ICommand SayCommand2 { get; private set; }

        private void InitCommand2()
        {
            SayCommand2 = new SayCommand2();
        }

源代码

作者:FoolRabbit(百度ID:一个人『等待』)
出处:http://blog.csdn.net/rabbitsoft_1987
欢迎任何形式的转载,未经作者同意,请保留此段声明!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FoolRabbit

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

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

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

打赏作者

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

抵扣说明:

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

余额充值