命令可以看做事件的进化版,使用命令,可以使代码结构更清晰;还能更好的控制各个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
欢迎任何形式的转载,未经作者同意,请保留此段声明!