命令(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來進行命令綁定,在命令裏面實現了相關的業務處理,使代碼更清晰。
下面用自定義命令來實現上面的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
歡迎任何形式的轉載,未經作者同意,請保留此段聲明!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章