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开发

相关推荐
beyond谚语17 小时前
第一章 WPF概述
wpf
necessary6531 天前
从工行“余额归零”事件看CAP定理:当金融系统在一致性与可用性之间做出选择
分布式·金融·wpf·可用性测试
棉晗榜1 天前
WPF隐藏控件后,怎么让其上部的控件空间自动撑高
wpf
壹佰大多2 天前
【Redisson分布式锁源码分析-3】
数据结构·分布式·mysql·spring·spring cloud·wpf·lua
LateFrames3 天前
以小白视角尝试 WPF / WinUI3 / MAUI / MAUI Blazor 构建 Windows 桌面程序
windows·wpf·maui·mauiblazor·winui3
偶尔的鼠标人3 天前
Avalonia/WPF 打开子窗口,并且跨页面传值
c#·wpf·mvvm·avalonia
玖笙&3 天前
✨WPF编程进阶【6.1】:图形原则(附源码)
c++·c#·wpf·visual studio
lixy5793 天前
WPF检测网络状态切换
wpf
纸照片3 天前
WPF中为Button设置IsMouseOver和IsPressed事件中改变背景颜色不起作用
c#·.net·wpf
Aevget3 天前
DevExpress WPF中文教程:Data Grid - 如何使用虚拟源?(四)
ui·.net·wpf·devexpress·wpf控件