wpf 命令理解

命令包含RouteCommand和CustomCommand类

RouteCommand

通常用于自定义控件,或者入门学习时用

本身仅定义命令标识,必须通过 CommandBinding 关联执行逻辑,以下代码的CommandBinding是后台代码添加的Windows.CommandBinding.Add();

如果不是后台代码,用xaml语言的话

cs 复制代码
<Window.Resources>
<RoutedUICommand x:Key="PlayCommand" Text="Open"/>
</Window.Resources>

<Window.CommandBindings>
<CommandBinding Command="{StaticResource PlayCommand}"
                Executed="CommandBinding_Executed"
                CanExecute="CommandBinding_CanExecute"/>
</Window.CommandBindings>

后台代码

cs 复制代码
using System;
using System.Windows;
using System.Windows.Input;

// 自定义命令类(使用RoutedCommand实现路由功能)
public static class CustomCommands
{
    // 声明命令
    public static readonly RoutedCommand Save = new RoutedCommand(
        "Save",                  // 命令名称
        typeof(CustomCommands),  // 所属类型
        new InputGestureCollection  // 可选:定义快捷键
        {
            new KeyGesture(Key.S, ModifierKeys.Control)  // Ctrl+S
        }
    );

    public static readonly RoutedCommand Delete = new RoutedCommand(
        "Delete", 
        typeof(CustomCommands),
        new InputGestureCollection
        {
            new KeyGesture(Key.Delete)  // Delete键
        }
    );
}

// 命令执行逻辑(通常在ViewModel或代码后台实现)
public class CommandHandler
{
    // 注册命令绑定
    public static void RegisterCommandBindings(UIElement element)
    {
        // 保存命令绑定
        element.CommandBindings.Add(new CommandBinding(
            CustomCommands.Save,
            Save_Executed,       // 执行逻辑
            Save_CanExecute      // 能否执行的判断
        ));

        // 删除命令绑定
        element.CommandBindings.Add(new CommandBinding(
            CustomCommands.Delete,
            Delete_Executed,
            Delete_CanExecute
        ));
    }

    // 保存命令执行
    private static void Save_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        // 实际保存逻辑
        MessageBox.Show("执行保存操作");
        e.Handled = true;
    }

    // 保存命令是否可执行
    private static void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        // 这里可以根据条件判断是否允许执行(例如:数据是否已修改)
        e.CanExecute = true;  // 始终允许执行
        e.Handled = true;
    }

    // 删除命令执行
    private static void Delete_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        // 实际删除逻辑
        if (MessageBox.Show("确定要删除吗?", "提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        {
            MessageBox.Show("执行删除操作");
        }
        e.Handled = true;
    }

    // 删除命令是否可执行
    private static void Delete_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        // 例如:只有选中项存在时才允许删除
        e.CanExecute = true;  // 简化示例,始终允许
        e.Handled = true;
    }
}
cs 复制代码
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

// 模拟RoutedCommand的核心实现
public class MyRoutedCommand
{
    // 命令元数据
    public string Name { get; }
    public Type OwnerType { get; }
    public InputGestureCollection InputGestures { get; }

    // 构造函数:初始化命令元数据
    public MyRoutedCommand(string name, Type ownerType, InputGestureCollection inputGestures = null)
    {
        Name = name;
        OwnerType = ownerType;
        InputGestures = inputGestures ?? new InputGestureCollection();
    }

    // 执行命令:核心方法
    public void Execute(object parameter, IInputElement target)
    {
        if (target == null) return;

        // 1. 创建命令执行事件参数
        var args = new ExecutedRoutedEventArgs(this, parameter)
        {
            Source = target
        };

        // 2. 在目标元素上触发路由事件(冒泡)
        target.RaiseEvent(args);

        // 3. 如果事件未被处理,继续向上传播(简化逻辑)
        if (!args.Handled)
        {
            var parent = VisualTreeHelper.GetParent(target as DependencyObject);
            if (parent is IInputElement parentElement)
            {
                Execute(parameter, parentElement); // 递归向上查找处理者
            }
        }
    }

    // 判断命令是否可执行
    public bool CanExecute(object parameter, IInputElement target)
    {
        if (target == null) return false;

        // 1. 创建可用性判断事件参数
        var args = new CanExecuteRoutedEventArgs(this, parameter)
        {
            Source = target,
            CanExecute = false // 默认不可执行
        };

        // 2. 在目标元素上触发路由事件
        target.RaiseEvent(args);

        // 3. 如果未找到处理者,继续向上传播
        if (!args.Handled)
        {
            var parent = VisualTreeHelper.GetParent(target as DependencyObject);
            if (parent is IInputElement parentElement)
            {
                return CanExecute(parameter, parentElement);
            }
        }

        return args.CanExecute;
    }
}

// 配套的路由事件参数(简化版)
public class ExecutedRoutedEventArgs : RoutedEventArgs
{
    public MyRoutedCommand Command { get; }
    public object Parameter { get; }

    public ExecutedRoutedEventArgs(MyRoutedCommand command, object parameter)
    {
        Command = command;
        Parameter = parameter;
        RoutedEvent = CommandManager.ExecutedEvent; // 关联命令系统的执行事件
    }
}

public class CanExecuteRoutedEventArgs : RoutedEventArgs
{
    public MyRoutedCommand Command { get; }
    public object Parameter { get; }
    public bool CanExecute { get; set; }

    public CanExecuteRoutedEventArgs(MyRoutedCommand command, object parameter)
    {
        Command = command;
        Parameter = parameter;
        RoutedEvent = CommandManager.CanExecuteEvent; // 关联可用性判断事件
    }
}

CustomCommand类

继承ICommand,命名为RelayCommand或者DelegateCommand

在viewmodel中声明初始化

常用于MVVM开发

相关推荐
是木子啦4 小时前
wpf passwordbox控件 光标移到最后
c#·wpf
布伦鸽5 小时前
C# WPF DataGrid使用Observable<Observable<object>类型作为数据源
开发语言·c#·wpf
分布式存储与RustFS17 小时前
告别复杂配置:用Milvus、RustFS和Vibe Coding,60分钟DIY专属Chatbot
wpf·文件系统·milvus·对象存储·minio·rustfs·vibe
攻城狮CSU1 天前
WPF 绑定机制实现原理
wpf
攻城狮CSU1 天前
WPF 之数据绑定一(Data Binding)
wpf
wuty0072 天前
记录一下 WPF进程 SendMessage 发送窗口消息进行进程间通信,存在进程权限无法接受消息的问题
wpf·进程间通信·sendmessage·进程权限
c#上位机2 天前
wpf之ToggleButton控件
c#·wpf
浪扼飞舟2 天前
WPF用户控件和依赖属性
wpf
c#上位机3 天前
wpf之MVVM中只读属性更新界面
c#·wpf·mvvm