命令可以看做事件的進化版,使用命令,可以使代碼結構更清晰;還能更好的控制各個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在執行前來幫助判斷是不是可以執行、在執行後處理什麼任務。
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
歡迎任何形式的轉載,未經作者同意,請保留此段聲明!