WPF命令绑定核心是ICommand接口,推荐用RelayCommand实现解耦与自动启停;需在属性变更后调用CommandManager.InvalidateRequerySuggested刷新状态,RoutedCommand适用于跨控件共享或快捷键场景。

WPF 中命令绑定的核心是 ICommand 接口,它让 UI 操作(比如按钮点击)和业务逻辑解耦,比直接写 Click 事件更灵活、可测试、支持自动启停(如按钮灰化)。下面用最常用也最实用的方式讲清楚怎么用。
用 RelayCommand 实现 ICommand(推荐新手)
WPF 自身没提供 ICommand 的默认实现,但社区广泛使用 RelayCommand(也叫 DelegateCommand)——它用 Action 和 Func 封装执行逻辑和判断逻辑,轻量又直观。
- 先定义一个简单的 RelayCommand 类(几行代码就能写完):
public class RelayCommand : ICommand
{
private readonly Action _execute;
private readonly Func_canExecute;
public RelayCommand(Action execute, FunccanExecute = null)
{
_execute = execute;
_canExecute = canExecute ?? (() => true);
}
public bool CanExecute(object parameter) => _canExecute();
public void Execute(object parameter) => _execute();
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
}
- 在 ViewModel 中声明命令属性:
public class MainViewModel
{
public ICommand SaveCommand { get; }
public MainViewModel()
{
SaveCommand = new RelayCommand(OnSave, CanSave);
}
private void OnSave() => MessageBox.Show("已保存");
private bool CanSave() => !string.IsNullOrWhiteSpace(Title); // 假设有个 Title 属性
}
XAML 中绑定命令(不写后台代码)
把按钮的 Command 属性直接绑定到 ViewModel 的 ICommand 属性,WPF 会自动调用 Execute,并根据 CanExecute 结果控制是否启用。
- 确保 DataContext 已设为 ViewModel(例如在窗口构造函数中:DataContext = new MainViewModel())
- XAML 写法简洁明了:
- 如果命令需要传参(比如删除某一行),加 CommandParameter:
处理 CanExecute 变化(让按钮自动启停)
命令能否执行不是一成不变的,比如输入框为空时“保存”按钮应禁用。WPF 不会自动监听你的属性变化,得手动通知。
- RelayCommand 中已订阅 CommandManager.RequerySuggested,这是个“全局刷新信号”
- 你在 ViewModel 中修改影响 CanExecute 的属性(如 Title)后,手动触发一次刷新:
private string _title;
public string Title
{
get => _title;
set
{
_title = value;
OnPropertyChanged(); // INotifyPropertyChanged 实现
CommandManager.InvalidateRequerySuggested(); // 关键!告诉 WPF 重新查 CanExecute
}
}
用内置 RoutedCommand(适合菜单/快捷键等系统级操作)
如果你需要响应 Ctrl+S、或让多个控件共用一个命令(比如“复制”在菜单和工具栏都可用),用 WPF 自带的 RoutedCommand 更合适。
- 定义静态命令对象(通常放在资源字典或 App.xaml.cs):
public static class ApplicationCommands
{
public static readonly RoutedCommand Save = new RoutedCommand();
}
- 在窗口中绑定命令并处理执行逻辑(通过 CommandBinding):
Executed="OnSaveExecuted"
CanExecute="OnSaveCanExecute"/>
- 后台代码里写逻辑:
private void OnSaveExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("RoutedCommand 保存");
}
private void OnSaveCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = !string.IsNullOrEmpty(Title);
}
基本上就这些。RelayCommand + Binding 是日常开发主力,RoutedCommand 用在需要路由或跨控件共享的场景。不复杂但容易忽略 CommandManager.InvalidateRequerySuggested 这一步——少了它,按钮状态就不会自动更新。










