在C#的WPF、MAUI等界面开发框架中,命令模式是实现界面交互逻辑与业务逻辑解耦的重要方案,ICommand接口是框架内置的命令定义标准,掌握其实现方式能让交互代码更清晰、更易维护。

ICommand接口核心定义
ICommand是System.Windows.Input命名空间下的接口,定义了命令的基础行为,包含三个核心成员:
- Execute方法:命令触发时执行的具体业务逻辑,接收一个object类型的参数
- CanExecute方法:判断命令当前是否可执行,返回bool值,界面会根据返回值自动更新按钮等控件的启用状态
- CanExecuteChanged事件:当命令的可执行状态发生变化时触发,通知界面更新控件状态
接口的基础定义如下:
using System;
using System.Windows.Input;
namespace CommandDemo
{
public interface ICommand
{
// 执行命令逻辑
void Execute(object parameter);
// 判断命令是否可执行
bool CanExecute(object parameter);
// 可执行状态变化事件
event EventHandler CanExecuteChanged;
}
}
自定义RelayCommand实现类
实际开发中我们不会直接实现ICommand,而是封装一个通用的RelayCommand类,减少重复代码,支持传入委托定义命令逻辑:
using System;
using System.Windows.Input;
namespace CommandDemo
{
public class RelayCommand : ICommand
{
// 存储执行逻辑的委托
private readonly Action<object> _execute;
// 存储可执行判断逻辑的委托
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
// 如果没有传入判断委托,默认命令始终可执行
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
// 手动触发可执行状态更新
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
}
结合ViewModel实现命令绑定
命令模式通常和MVVM模式配合使用,我们在ViewModel中定义命令属性,绑定到界面的控件上:
ViewModel基础实现
ViewModel需要实现INotifyPropertyChanged接口,通知界面属性变化:
using System;
using System.ComponentModel;
using System.Windows.Input;
namespace CommandDemo
{
public class MainViewModel : INotifyPropertyChanged
{
private string _inputText;
private bool _isSubmitEnabled;
// 输入文本属性
public string InputText
{
get { return _inputText; }
set
{
_inputText = value;
OnPropertyChanged(nameof(InputText));
// 输入文本变化时,更新提交命令的可执行状态
SubmitCommand.RaiseCanExecuteChanged();
}
}
// 提交命令
public RelayCommand SubmitCommand { get; private set; }
public MainViewModel()
{
// 初始化命令,传入执行逻辑和可执行判断逻辑
SubmitCommand = new RelayCommand(
parameter =>
{
// 执行提交逻辑,这里模拟弹出输入内容
System.Windows.MessageBox.Show($"提交内容:{InputText}");
},
parameter =>
{
// 输入文本长度大于0时命令可执行
return !string.IsNullOrEmpty(InputText);
}
);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
界面XAML绑定示例
在WPF界面中,将按钮的Command属性绑定到ViewModel的SubmitCommand,CommandParameter可以传递参数:
<Window x:Class="CommandDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CommandDemo"
Title="命令模式示例" Height="300" Width="400">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<StackPanel Margin="20">
<TextBox Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"
Height="30" Margin="0 0 0 10"
Placeholder="请输入内容"/>
<Button Content="提交"
Height="30"
Command="{Binding SubmitCommand}"
CommandParameter="{Binding InputText}"/>
</StackPanel>
</Window>
命令模式进阶注意事项
- 如果命令不需要参数,Execute和CanExecute的parameter可以传入null,也可以在RelayCommand中封装无参版本
- 当命令的可执行状态依赖多个属性变化时,需要在所有相关属性变化时调用RaiseCanExecuteChanged方法
- 对于复用性高的命令逻辑,可以封装成独立的命令类,避免ViewModel中逻辑冗余
- 异步命令的实现需要注意,Execute方法中不要直接执行耗时操作,应该启动异步任务,同时更新命令的可执行状态防止重复触发
异步命令实现示例
针对需要执行异步操作的场景,我们可以封装AsyncRelayCommand:
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace CommandDemo
{
public class AsyncRelayCommand : ICommand
{
private readonly Func<object, Task> _execute;
private readonly Func<object, bool> _canExecute;
private bool _isExecuting;
public AsyncRelayCommand(Func<object, Task> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
// 正在执行时命令不可执行,避免重复触发
return !_isExecuting && (_canExecute == null || _canExecute(parameter));
}
public async void Execute(object parameter)
{
if (_isExecuting) return;
_isExecuting = true;
RaiseCanExecuteChanged();
try
{
await _execute(parameter);
}
finally
{
_isExecuting = false;
RaiseCanExecuteChanged();
}
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
}
通过自定义RelayCommand和AsyncRelayCommand,我们可以覆盖大部分C#交互开发中的命令场景,让界面逻辑和业务逻辑完全解耦,提升代码的可维护性和复用性。
C#_ICommand命令模式命令绑定INotifyPropertyChangedRelayCommand修改时间:2026-07-11 12:00:41