前言
wpf中命令Command主要用于将 UI 控件(如按钮、菜单项)的触发动作与执行该动作的逻辑代码解耦,主要在MVVM模式使用。
1、命令的三个核心概念
1.1 命令源
命令源是触发命令的 UI 元素,它实现了 ICommandSource 接口,例如 Button、MenuItem、KeyGesture(快捷键),我们最常用的就是鼠标左键点击Button来触发命令,这里的Button就是命令源,一般通过设置命令源的 Command 属性来关联一个命令,比如下面的代码中设置Command属性的值为"ApplicationCommands.Paste",就是关联了一个复制命令。
csharp
<Button Content="粘贴"
Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=TargetTextBox}"
Width="40" />
1.2 命令目标
命令目标是命令执行操作的对象。通常是拥有焦点的控件。可以通过命令源的 CommandTarget 属性显式设置,如果未设置,则默认为拥有键盘焦点的元素,比如下面的代码 CommandTarget="{Binding ElementName=TargetTextBox}"就是指定了命令操作的对象是TargetTextBox这个TextBox控件。
csharp
<Button Content="粘贴"
Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=TargetTextBox}"
Width="40" />
<TextBox x:Name="TargetTextBox" Width=" 40" Height=" 20"/>
1.3 命令绑定
命令绑定指定了两件事,一个是当命令被执行时,运行什么代码(对应 Execute方法);另一个是
命令何时可以执行(对应 CanExecute方法),这两个方法都是在接口ICommand中定义,对于部分命令比如"ApplicationCommands.Copy"、"ApplicationCommands.Paste"不需要我们自己写命令绑定,但是一般自定义的命令需要我们自己重写 CanExecute和 Execute方法。
csharp
public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}
2、系统自带命令
任何实现了 ICommand 接口的类都可以作为 WPF 命令
2.1 复制和粘贴

下面的代码中我们先用鼠标选中"123"中的"23",然后点击"复制"按钮,最后点击"粘贴"按钮,这样你就能看到文本"23"被粘贴到最下方的TextBox 中,点击"复制"按钮时就是执行了"ApplicationCommands.Copy"命令,点击"粘贴"按钮就是执行"ApplicationCommands.Paste"命令。
csharp
<Window x:Class="wpf之命令.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf之命令"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel >
<Button Content="复制" Width=" 40" Height=" 20" Command="ApplicationCommands.Copy" CommandTarget="{Binding ElementName= tbx_test }" />
<TextBox x:Name="tbx_test" Width=" 40" Height=" 20"/>
<Button Content="粘贴"
Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=TargetTextBox}"
Width="40" />
<TextBox x:Name="TargetTextBox" Width=" 40" Height=" 20"/>
</StackPanel >
</Grid>
</Window>
3、自定义命令
3.1 MVVM模式-无参数命令
当点击按钮"MVVM模式"时,会触发cmd_test命令绑定的Test方法执行,这样会在控制台打印"自定义命令,参数:"
csharp
<Window x:Class="wpf之命令.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf之命令"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel >
<Button Width="80" Height=" 20" Content="MVVM模式" Command="{Binding cmd_test}" />
</StackPanel >
</Grid>
</Window>
csharp
public class DelegateCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
{
return _canExecute(parameter);
}
else
{
return true;
}
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
csharp
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propname));
}
}
}
csharp
public class ViewModel : ViewModelBase
{
public DelegateCommand cmd_test { get; set; }
public ViewModel()
{
cmd_test = new DelegateCommand(Test);
}
private void Test(object param)
{
Console.WriteLine($"自定义命令,参数:{param}");
}
}
3.2 MVVM模式-有参数命令
当点击按钮"MVVM模式-有参"时,会触发cmd_test命令绑定的Test方法执行,这样会在控制台打印"自定义命令,参数:123"
csharp
<Window x:Class="wpf之命令.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf之命令"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel Height="419" VerticalAlignment="Bottom" >
<Button Width="120" Height=" 20" Content="MVVM模式-有参" Command="{Binding cmd_test}" CommandParameter="123" />
</StackPanel >
</Grid>
</Window>