在WPF(Windows Presentation Foundation)开发中,命令(Command)是一种非常重要的设计模式,它允许我们将用户界面操作(如按钮点击)与业务逻辑解耦。这种机制的核心就是 ICommand 接口。本教程将带你从零开始,深入浅出地理解 WPF命令 的工作原理,并手把手教你如何实现一个实用的 RelayCommand 类。
ICommand 是 .NET 中定义的一个接口,位于 System.Windows.Input 命名空间下。它包含两个方法和一个事件:
Execute(object parameter):执行命令时调用的方法。CanExecute(object parameter):返回一个布尔值,表示当前命令是否可以执行。CanExecuteChanged:当命令能否执行的状态发生变化时触发的事件。通过实现这个接口,我们可以将 UI 控件(如 Button、MenuItem)绑定到 ViewModel 中的命令属性,从而实现 WPF MVVM 模式 中的“命令绑定”。

在传统的 WinForms 开发中,我们通常直接在按钮的 Click 事件中编写业务逻辑。但在 WPF 的 MVVM 模式 中,View(视图)和 ViewModel(视图模型)应尽量解耦。使用命令的好处包括:
虽然你可以每次都手动实现 ICommand,但更常见的做法是创建一个通用的 RelayCommand 类。下面是一个标准实现:
using System;using System.Windows.Input;public class RelayCommand : ICommand{ private readonly Action _execute; private readonly Func<bool>? _canExecute; public event EventHandler? CanExecuteChanged { add => CommandManager.RequerySuggested += value; remove => CommandManager.RequerySuggested -= value; } public RelayCommand(Action execute, Func<bool>? canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object? parameter) => _canExecute == null || _canExecute(); public void Execute(object? parameter) => _execute();}这个类接受两个委托:
Action execute:命令执行时要运行的代码。Func<bool> canExecute(可选):决定命令是否可用的条件。假设我们要实现一个“保存”按钮,只有当用户输入了内容后才启用。以下是一个简单的 ViewModel 示例:
using System.ComponentModel;using System.Runtime.CompilerServices;public class MainViewModel : INotifyPropertyChanged{ private string _inputText = ""; public string InputText { get => _inputText; set { _inputText = value; OnPropertyChanged(); // 通知命令状态可能已改变 SaveCommand.OnCanExecuteChanged(); } } public ICommand SaveCommand { get; } public MainViewModel() { SaveCommand = new RelayCommand( execute: SaveData, canExecute: () => !string.IsNullOrWhiteSpace(InputText) ); } private void SaveData() { // 模拟保存操作 System.Diagnostics.Debug.WriteLine($"保存内容: {InputText}"); } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }}最后,在 XAML 视图中,将按钮的 Command 属性绑定到 ViewModel 中的命令:
<Window x:Class="MyApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF 命令示例" Height="200" Width="400"> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> <StackPanel Margin="20"> <TextBox Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" Height="30" Margin="0,0,0,10"/> <Button Content="保存" Command="{Binding SaveCommand}" Height="35" FontSize="14"/> </StackPanel></Window>现在,当你在文本框中输入内容时,“保存”按钮会自动启用;清空内容后,按钮又会自动禁用。这就是 WPF命令 与 ICommand接口 的强大之处!
通过本教程,你已经掌握了:
ICommand 接口及其在 WPF 中的作用。RelayCommand 类。掌握这些知识后,你就能更优雅地构建可维护、可测试的 WPF 应用程序。继续练习吧,你会发现 WPF MVVM 模式 和 RelayCommand 实现 是现代 WPF 开发的基石!