Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 6.2 命令绑定与交互

6.2 命令绑定与交互

核心概念

ICommand接口

  • 定义:System.Windows.Input.ICommand是WPF命令系统的核心接口
  • 关键方法:
    • Execute(object parameter):执行命令逻辑
    • CanExecute(object parameter):确定命令是否可执行
    • CanExecuteChanged:通知命令状态变化的事件

常用实现方式

  1. RoutedCommand
    WPF内置的路由命令实现,适合UI层简单交互

  2. RelayCommand/DelegateCommand
    MVVM模式下的典型实现方案:

    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;
    
        public RelayCommand(Action<object> execute, 
                           Predicate<object> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
    
        public bool CanExecute(object parameter) 
            => _canExecute?.Invoke(parameter) ?? true;
    
        public void Execute(object parameter) 
            => _execute(parameter);
    
        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }
    }
    

实战应用

XAML中的命令绑定

<Button Content="保存"
        Command="{Binding SaveCommand}"
        CommandParameter="{Binding SelectedItem}"/>

ViewModel中的命令实现

public class DocumentViewModel : INotifyPropertyChanged
{
    public ICommand SaveCommand { get; }

    public DocumentViewModel()
    {
        SaveCommand = new RelayCommand(
            execute: param => SaveDocument(param),
            canExecute: param => IsDocumentValid
        );
    }

    private void SaveDocument(object parameter)
    {
        // 保存逻辑实现
    }
}

高级交互模式

复合命令

public class CompositeCommand : ICommand
{
    private readonly List<ICommand> _commands = new List<ICommand>();

    public void RegisterCommand(ICommand command) 
        => _commands.Add(command);

    public bool CanExecute(object parameter)
        => _commands.All(cmd => cmd.CanExecute(parameter));

    public void Execute(object parameter)
    {
        foreach (var cmd in _commands)
        {
            cmd.Execute(parameter);
        }
    }

    // 事件实现省略...
}

命令参数传递技巧

  1. 直接绑定对象属性

    <Button Command="{Binding EditCommand}" 
            CommandParameter="{Binding CurrentItem}"/>
    
  2. 使用MultiBinding

    <Button.Content>
        <MultiBinding Converter="{StaticResource ParamConverter}">
            <Binding Path="UserName"/>
            <Binding Path="UserRole"/>
        </MultiBinding>
    </Button.Content>
    

最佳实践

  1. 命令与方法的区别

    • 命令支持启用/禁用状态管理
    • 命令可被多个UI元素共享
    • 命令支持路由事件
  2. 性能优化建议

    • 避免在CanExecute中执行复杂逻辑
    • 对高频操作命令使用命令缓存
    • 及时注销CanExecuteChanged事件处理器
  3. 调试技巧

    CommandManager.AddCanExecuteHandler(this, (s, e) => 
        Debug.WriteLine($"Command {e.Command} can execute: {e.CanExecute}"));
    

常见问题解决方案

问题现象可能原因解决方案
命令不触发DataContext未正确设置检查绑定路径和DataContext继承链
CanExecute状态不更新未触发RequerySuggested事件调用CommandManager.InvalidateRequerySuggested()
参数传递失败参数类型不匹配使用ValueConverter进行类型转换
Last Updated:: 5/3/25, 10:42 PM