接上一篇《WPF笔记汇总之数据绑定及依赖属性》,这篇主要总结WPF特有的关于命令的用法,包括系统命令使用及自定义命令的创建及使用。
在WPF中,允许在一个地方定义命令,并且在所有的用户接口控件之中调用这些命令,它们由ICommand接口组成,该接口仅定义一个事件和两个方法:Execute()和CanExecute()。第一个用于执行实际操作,而第二个用于确定操作当前是否可用。要执行命令的实际操作,您需要在命令和代码之间使用CommandBinding作为链接,CommandBinding通常在Window或UserControl上定义,并保存对它处理的Command的引用,以及用于处理Command的Execute()和CanExecute()事件的实际事件处理程序。
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" CommandTarget="{Binding ElementName=txtEditor}" Width="60">_CutButton>
<Button Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=txtEditor}" Width="60" Margin="3,0">_PasteButton>
WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
DockPanel>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Cut" CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
<CommandBinding Command="ApplicationCommands.Paste" CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
Window.CommandBindings>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut" Width="60">_CutButton>
<Button Command="ApplicationCommands.Paste" Width="60" Margin="3,0">_PasteButton>
WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
DockPanel>
private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = (txtEditor != null) && (txtEditor.SelectionLength > 0);
}
private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Cut();
}
private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = Clipboard.ContainsText();
}
private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
txtEditor.Paste();
}
class CustomCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public void Execute(object param)
{
ExecuteAction?.Invoke(param);
}
public bool CanExecute(object param)
{
if (CanExecuteAction != null)
return CanExecuteAction(param);
return false;
}
public Action<object> ExecuteAction { get; set; }
public Func<object, bool> CanExecuteAction { get; set; }
}
public CustomCommand MyCommand { get; set; }
public void DoSomething(object param){
}
public bool CanDoSomething(object param){
return true;
}
public MyViewModel(){
MyCommand = new CustomCommand();
MyCommand.ExecuteAction = new Action<object>(this.DoSomething);
MyCommand.CanExecuteAction = new Func<object, bool>(this.CanDoSomething);
}
<Window xmlns:vm="clr-namespace:MyApp.ViewModel" ... />
<Grid>
<Grid.DataContext>
<vm:MyViewModel>
Grid.DataContext>
<Button Content="Click here" Command="{Binding MyCommand}" />
Grid>
Window>
public static class CustomCommands
{
public static readonly RoutedUICommand ExitCommand = new RoutedUICommand(
"quit app",
"ExitCommand",
typeof(CustomCommands),
new InputGestureCollection() {
new KeyGesture(Key.W, ModifierKeys.Control)
});
}
public void ExitCommand_Execute(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
public void ExitCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
<Window.CommandBindings>
<CommandBinding Command="local:CustomCommands.ExitCommand"
CanExecute="ExitCommand_CanExecute"
Executed="ExitCommand_Execute"/>
Window.CommandBindings>
<Button Content="Exit" Command="local:CustomCommands.ExitCommand"/>