找回密码
 立即注册
首页 业界区 业界 回顾一下WPF原生实现命令

回顾一下WPF原生实现命令

时思美 2025-9-28 18:03:22
前言

最近在学习Stylet中Command="{s:Action 方法名}"的设计与实现,但要弄明白这个之前,必须对原生实现命令比较熟悉,一想我也很久没有自己实现原生的命令了,之前都是用Community.Mvvm库来实现,所以今天先来回顾一下,在WPF中如何实现原生的命令。
借助AI使用原生的WPF写法实现了一个跟Stylet例子Hello一样的效果:
1.png

WPF中如何使用命令

WPF命令是实现用户界面交互的核心机制,通过实现ICommand接口来封装可执行的操作。命令支持松耦合的UI设计,可以绑定到按钮、菜单等控件,实现统一的执行逻辑。WPF提供了丰富的内置命令如ApplicationCommands、NavigationCommands等,同时也支持自定义命令,便于实现撤销/重做、数据绑定等复杂功能。
现在先来看看这个例子中是如何使用命令的吧!!
  1. public class RelayCommand : ICommand
  2. {
  3.   <Button Content="Say Hello"
  4.           Command="{Binding SayHelloCommand}"
  5.           Height="30"
  6.           FontSize="14"/>  <Button Content="Say Hello"
  7.           Command="{Binding SayHelloCommand}"
  8.           Height="30"
  9.           FontSize="14"/> private readonly Action<object?> _execute;
  10.   <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/>  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/> private readonly Predicate<object?>? _canExecute;
  17.   <Button Content="Say Hello"
  18.           Command="{Binding SayHelloCommand}"
  19.           Height="30"
  20.           FontSize="14"/>  <Button Content="Say Hello"
  21.           Command="{Binding SayHelloCommand}"
  22.           Height="30"
  23.           FontSize="14"/> public RelayCommand(Action<object?> execute, Predicate<object?>? canExecute = null)
  24.   <Button Content="Say Hello"
  25.           Command="{Binding SayHelloCommand}"
  26.           Height="30"
  27.           FontSize="14"/>  <Button Content="Say Hello"
  28.           Command="{Binding SayHelloCommand}"
  29.           Height="30"
  30.           FontSize="14"/> {
  31.   <Button Content="Say Hello"
  32.           Command="{Binding SayHelloCommand}"
  33.           Height="30"
  34.           FontSize="14"/>  <Button Content="Say Hello"
  35.           Command="{Binding SayHelloCommand}"
  36.           Height="30"
  37.           FontSize="14"/>  <Button Content="Say Hello"
  38.           Command="{Binding SayHelloCommand}"
  39.           Height="30"
  40.           FontSize="14"/>  <Button Content="Say Hello"
  41.           Command="{Binding SayHelloCommand}"
  42.           Height="30"
  43.           FontSize="14"/> _execute = execute ?? throw new ArgumentNullException(nameof(execute));
  44.   <Button Content="Say Hello"
  45.           Command="{Binding SayHelloCommand}"
  46.           Height="30"
  47.           FontSize="14"/>  <Button Content="Say Hello"
  48.           Command="{Binding SayHelloCommand}"
  49.           Height="30"
  50.           FontSize="14"/>  <Button Content="Say Hello"
  51.           Command="{Binding SayHelloCommand}"
  52.           Height="30"
  53.           FontSize="14"/>  <Button Content="Say Hello"
  54.           Command="{Binding SayHelloCommand}"
  55.           Height="30"
  56.           FontSize="14"/> _canExecute = canExecute;
  57.   <Button Content="Say Hello"
  58.           Command="{Binding SayHelloCommand}"
  59.           Height="30"
  60.           FontSize="14"/>  <Button Content="Say Hello"
  61.           Command="{Binding SayHelloCommand}"
  62.           Height="30"
  63.           FontSize="14"/> }
  64.   <Button Content="Say Hello"
  65.           Command="{Binding SayHelloCommand}"
  66.           Height="30"
  67.           FontSize="14"/>  <Button Content="Say Hello"
  68.           Command="{Binding SayHelloCommand}"
  69.           Height="30"
  70.           FontSize="14"/> public event EventHandler? CanExecuteChanged
  71.   <Button Content="Say Hello"
  72.           Command="{Binding SayHelloCommand}"
  73.           Height="30"
  74.           FontSize="14"/>  <Button Content="Say Hello"
  75.           Command="{Binding SayHelloCommand}"
  76.           Height="30"
  77.           FontSize="14"/> {
  78.   <Button Content="Say Hello"
  79.           Command="{Binding SayHelloCommand}"
  80.           Height="30"
  81.           FontSize="14"/>  <Button Content="Say Hello"
  82.           Command="{Binding SayHelloCommand}"
  83.           Height="30"
  84.           FontSize="14"/>  <Button Content="Say Hello"
  85.           Command="{Binding SayHelloCommand}"
  86.           Height="30"
  87.           FontSize="14"/>  <Button Content="Say Hello"
  88.           Command="{Binding SayHelloCommand}"
  89.           Height="30"
  90.           FontSize="14"/> add => CommandManager.RequerySuggested += value;
  91.   <Button Content="Say Hello"
  92.           Command="{Binding SayHelloCommand}"
  93.           Height="30"
  94.           FontSize="14"/>  <Button Content="Say Hello"
  95.           Command="{Binding SayHelloCommand}"
  96.           Height="30"
  97.           FontSize="14"/>  <Button Content="Say Hello"
  98.           Command="{Binding SayHelloCommand}"
  99.           Height="30"
  100.           FontSize="14"/>  <Button Content="Say Hello"
  101.           Command="{Binding SayHelloCommand}"
  102.           Height="30"
  103.           FontSize="14"/> remove => CommandManager.RequerySuggested -= value;
  104.   <Button Content="Say Hello"
  105.           Command="{Binding SayHelloCommand}"
  106.           Height="30"
  107.           FontSize="14"/>  <Button Content="Say Hello"
  108.           Command="{Binding SayHelloCommand}"
  109.           Height="30"
  110.           FontSize="14"/> }
  111.   <Button Content="Say Hello"
  112.           Command="{Binding SayHelloCommand}"
  113.           Height="30"
  114.           FontSize="14"/>  <Button Content="Say Hello"
  115.           Command="{Binding SayHelloCommand}"
  116.           Height="30"
  117.           FontSize="14"/> public bool CanExecute(object? parameter)
  118.   <Button Content="Say Hello"
  119.           Command="{Binding SayHelloCommand}"
  120.           Height="30"
  121.           FontSize="14"/>  <Button Content="Say Hello"
  122.           Command="{Binding SayHelloCommand}"
  123.           Height="30"
  124.           FontSize="14"/> {
  125.   <Button Content="Say Hello"
  126.           Command="{Binding SayHelloCommand}"
  127.           Height="30"
  128.           FontSize="14"/>  <Button Content="Say Hello"
  129.           Command="{Binding SayHelloCommand}"
  130.           Height="30"
  131.           FontSize="14"/>  <Button Content="Say Hello"
  132.           Command="{Binding SayHelloCommand}"
  133.           Height="30"
  134.           FontSize="14"/>  <Button Content="Say Hello"
  135.           Command="{Binding SayHelloCommand}"
  136.           Height="30"
  137.           FontSize="14"/> return _canExecute == null || _canExecute(parameter);
  138.   <Button Content="Say Hello"
  139.           Command="{Binding SayHelloCommand}"
  140.           Height="30"
  141.           FontSize="14"/>  <Button Content="Say Hello"
  142.           Command="{Binding SayHelloCommand}"
  143.           Height="30"
  144.           FontSize="14"/> }
  145.   <Button Content="Say Hello"
  146.           Command="{Binding SayHelloCommand}"
  147.           Height="30"
  148.           FontSize="14"/>  <Button Content="Say Hello"
  149.           Command="{Binding SayHelloCommand}"
  150.           Height="30"
  151.           FontSize="14"/> public void Execute(object? parameter)
  152.   <Button Content="Say Hello"
  153.           Command="{Binding SayHelloCommand}"
  154.           Height="30"
  155.           FontSize="14"/>  <Button Content="Say Hello"
  156.           Command="{Binding SayHelloCommand}"
  157.           Height="30"
  158.           FontSize="14"/> {
  159.   <Button Content="Say Hello"
  160.           Command="{Binding SayHelloCommand}"
  161.           Height="30"
  162.           FontSize="14"/>  <Button Content="Say Hello"
  163.           Command="{Binding SayHelloCommand}"
  164.           Height="30"
  165.           FontSize="14"/>  <Button Content="Say Hello"
  166.           Command="{Binding SayHelloCommand}"
  167.           Height="30"
  168.           FontSize="14"/>  <Button Content="Say Hello"
  169.           Command="{Binding SayHelloCommand}"
  170.           Height="30"
  171.           FontSize="14"/> _execute(parameter);
  172.   <Button Content="Say Hello"
  173.           Command="{Binding SayHelloCommand}"
  174.           Height="30"
  175.           FontSize="14"/>  <Button Content="Say Hello"
  176.           Command="{Binding SayHelloCommand}"
  177.           Height="30"
  178.           FontSize="14"/> }
  179.   <Button Content="Say Hello"
  180.           Command="{Binding SayHelloCommand}"
  181.           Height="30"
  182.           FontSize="14"/>  <Button Content="Say Hello"
  183.           Command="{Binding SayHelloCommand}"
  184.           Height="30"
  185.           FontSize="14"/> public void RaiseCanExecuteChanged()
  186.   <Button Content="Say Hello"
  187.           Command="{Binding SayHelloCommand}"
  188.           Height="30"
  189.           FontSize="14"/>  <Button Content="Say Hello"
  190.           Command="{Binding SayHelloCommand}"
  191.           Height="30"
  192.           FontSize="14"/> {
  193.   <Button Content="Say Hello"
  194.           Command="{Binding SayHelloCommand}"
  195.           Height="30"
  196.           FontSize="14"/>  <Button Content="Say Hello"
  197.           Command="{Binding SayHelloCommand}"
  198.           Height="30"
  199.           FontSize="14"/>  <Button Content="Say Hello"
  200.           Command="{Binding SayHelloCommand}"
  201.           Height="30"
  202.           FontSize="14"/>  <Button Content="Say Hello"
  203.           Command="{Binding SayHelloCommand}"
  204.           Height="30"
  205.           FontSize="14"/> CommandManager.InvalidateRequerySuggested();
  206.   <Button Content="Say Hello"
  207.           Command="{Binding SayHelloCommand}"
  208.           Height="30"
  209.           FontSize="14"/>  <Button Content="Say Hello"
  210.           Command="{Binding SayHelloCommand}"
  211.           Height="30"
  212.           FontSize="14"/> }
  213. }
复制代码
这个例子中自己实现了一个实现ICommand接口的RelayCommand类。
先来看看ICommand接口:
  1.   <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/>  <Button Content="Say Hello"
  5.           Command="{Binding SayHelloCommand}"
  6.           Height="30"
  7.           FontSize="14"/>public interface ICommand
  8.   <Button Content="Say Hello"
  9.           Command="{Binding SayHelloCommand}"
  10.           Height="30"
  11.           FontSize="14"/>  <Button Content="Say Hello"
  12.           Command="{Binding SayHelloCommand}"
  13.           Height="30"
  14.           FontSize="14"/>{
  15.   <Button Content="Say Hello"
  16.           Command="{Binding SayHelloCommand}"
  17.           Height="30"
  18.           FontSize="14"/>  <Button Content="Say Hello"
  19.           Command="{Binding SayHelloCommand}"
  20.           Height="30"
  21.           FontSize="14"/>  <Button Content="Say Hello"
  22.           Command="{Binding SayHelloCommand}"
  23.           Height="30"
  24.           FontSize="14"/>  <Button Content="Say Hello"
  25.           Command="{Binding SayHelloCommand}"
  26.           Height="30"
  27.           FontSize="14"/>event EventHandler? CanExecuteChanged;
  28.   <Button Content="Say Hello"
  29.           Command="{Binding SayHelloCommand}"
  30.           Height="30"
  31.           FontSize="14"/>  <Button Content="Say Hello"
  32.           Command="{Binding SayHelloCommand}"
  33.           Height="30"
  34.           FontSize="14"/>  <Button Content="Say Hello"
  35.           Command="{Binding SayHelloCommand}"
  36.           Height="30"
  37.           FontSize="14"/>  <Button Content="Say Hello"
  38.           Command="{Binding SayHelloCommand}"
  39.           Height="30"
  40.           FontSize="14"/>bool CanExecute(object? parameter);
  41.   <Button Content="Say Hello"
  42.           Command="{Binding SayHelloCommand}"
  43.           Height="30"
  44.           FontSize="14"/>  <Button Content="Say Hello"
  45.           Command="{Binding SayHelloCommand}"
  46.           Height="30"
  47.           FontSize="14"/>  <Button Content="Say Hello"
  48.           Command="{Binding SayHelloCommand}"
  49.           Height="30"
  50.           FontSize="14"/>  <Button Content="Say Hello"
  51.           Command="{Binding SayHelloCommand}"
  52.           Height="30"
  53.           FontSize="14"/>void Execute(object? parameter);
  54.   <Button Content="Say Hello"
  55.           Command="{Binding SayHelloCommand}"
  56.           Height="30"
  57.           FontSize="14"/>  <Button Content="Say Hello"
  58.           Command="{Binding SayHelloCommand}"
  59.           Height="30"
  60.           FontSize="14"/>}
复制代码
这个ICommand接口起到了什么作用呢?

  • 统一命令规范:定义了命令的标准结构,包含执行方法Execute和状态判断方法CanExecute
  • 实现命令绑定:允许UI控件(如Button、MenuItem)通过Command属性绑定到具体命令实现
  • 控制可用性:CanExecute方法动态控制控件的启用/禁用状态,CanExecuteChanged事件通知UI更新状态
  • 参数传递:通过parameter参数在UI和命令逻辑间传递数据
  • 解耦UI与业务逻辑:将界面操作与具体实现分离,提高代码的可维护性和可测试性
在RelayCommand中:
  1. private readonly Action<object?> _execute;
  2. private readonly Predicate<object?>? _canExecute;
复制代码
_execute (Action): 存储要执行的操作委托
_canExecute (Predicate?): 存储判断命令是否可执行的谓词委托,可为 null
  1. public event EventHandler? CanExecuteChanged
  2. {
  3.   <Button Content="Say Hello"
  4.           Command="{Binding SayHelloCommand}"
  5.           Height="30"
  6.           FontSize="14"/>  <Button Content="Say Hello"
  7.           Command="{Binding SayHelloCommand}"
  8.           Height="30"
  9.           FontSize="14"/> add => CommandManager.RequerySuggested += value;
  10.   <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/>  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/> remove => CommandManager.RequerySuggested -= value;
  17. }
复制代码
这里出现了一个CommandManager:
2.png

WPF 中的 CommandManager 是一个帮助类,位于System.Windows.Input命名空间。它并不负责“执行命令”,而是为整个命令系统(RoutedCommand / RoutedUICommand)提供基础支撑,核心职责可以概括为四类:
1、处理路由命令的 4 个附加事件
CommandManager 预定义了 4 个 static 的 RoutedEvent,都是附加事件,所有 UIElement 都可以通过它们监听或引发命令相关路由事件:
附加事件触发时机典型用途PreviewCanExecuteEvent准备询问某命令能否执行时触发(隧道)用于全局或父级拦截“能否执行”判断CanExecuteEvent同上,但为冒泡阶段本地逻辑判断命令当前是否可用PreviewExecutedEvent准备执行命令时触发(隧道)做执行前的统一拦截,例如日志、撤销栈ExecutedEvent同上,但为冒泡阶段实际执行业务逻辑(如 Save、Cut、Paste)这里出现了隧道与冒泡两个概念,该如何理解呢?
在 WPF 路由事件体系中,隧道(Tunneling)与冒泡(Bubbling)是指事件在可视化树上传递的两个方向,想象成“从上到下”还是“从下到上”即可。与命令系统结合时,理解这两个方向就等于知道“谁先被通知”、“谁可以打断谁”。
树结构:
Window → Grid → StackPanel → Button
这是典型的一棵可视化树。
隧道(Preview……)→ 从根向叶
PreviewCanExecute / PreviewExecuted 这类以 Preview 开头的事件,先由 Window 收到,再依次 Grid、StackPanel,最后才到达实际声明 CommandBinding / 声明 InputBindings 的那个 Button。
作用:你可以在高层(例如 Window 一级)拦截事件,做“统一处理”或“统一否决”,比如给所有按钮加日志、在全局禁止某些快捷键等。只要沿途某级标记 e.Handled = true,它就终止继续向下传递。
冒泡(……无 Preview)→ 从叶向根
隧道阶段结束后如果仍然 Handled == false,则进入冒泡阶段。方向反过来:Button 先收到,再依次 StackPanel、Grid、Window。
作用:一般在最具体元素(Button)里决定命令是否可用或执行,而父容器只做辅助行为,如更新状态栏、刷新菜单对勾等。同样可以用 e.Handled = true 阻止再向上传。
2、提供 4 组 Add xxx Handler / Remove xxx Handler 的快捷方法
这些只是对 UIElement.AddHandler、RemoveHandler 的二次封装,方便挂接或注销上述 4 种附加事件,省去记忆事件标识符或强制转换类型的麻烦。
3、维护全局命令“有效性”通知:RequerySuggested
事件定义:public static event EventHandler RequerySuggested;
作用:当系统条件变化(键盘焦点变化、文本被修改、网络状态变更等)时,所有命令需要重新询问“是否能执行”。WPF 内部的按钮、菜单项等在订阅此事件后,就会再次调用 ICommand.CanExecute 来决定 IsEnabled。
手动触发:CommandManager.InvalidateRequerySuggested(); 会立即引发该事件,从而强制刷新所有绑定命令的可执行状态。
4、提供“类级别” CommandBinding / InputBinding 注册
RegisterClassCommandBinding(Type type, CommandBinding commandBinding)
为指定类型(而不仅是某个实例)注册 CommandBinding,在所有实例共享同一组绑定逻辑,等同于在静态构造函数里写:
  1. CommandManager.RegisterClassCommandBinding(
  2.   <Button Content="Say Hello"
  3.           Command="{Binding SayHelloCommand}"
  4.           Height="30"
  5.           FontSize="14"/>  <Button Content="Say Hello"
  6.           Command="{Binding SayHelloCommand}"
  7.           Height="30"
  8.           FontSize="14"/>  <Button Content="Say Hello"
  9.           Command="{Binding SayHelloCommand}"
  10.           Height="30"
  11.           FontSize="14"/>typeof(MyControl),
  12.   <Button Content="Say Hello"
  13.           Command="{Binding SayHelloCommand}"
  14.           Height="30"
  15.           FontSize="14"/>  <Button Content="Say Hello"
  16.           Command="{Binding SayHelloCommand}"
  17.           Height="30"
  18.           FontSize="14"/>  <Button Content="Say Hello"
  19.           Command="{Binding SayHelloCommand}"
  20.           Height="30"
  21.           FontSize="14"/>new CommandBinding(ApplicationCommands.Save, OnSaveExecuted, OnSaveCanExecute));
  22. RegisterClassInputBinding(Type type, InputBinding inputBinding)
复制代码
同样道理,为某个控件类统一注册快捷键:
  1. CommandManager.RegisterClassInputBinding(
  2.   <Button Content="Say Hello"
  3.           Command="{Binding SayHelloCommand}"
  4.           Height="30"
  5.           FontSize="14"/>  <Button Content="Say Hello"
  6.           Command="{Binding SayHelloCommand}"
  7.           Height="30"
  8.           FontSize="14"/>  <Button Content="Say Hello"
  9.           Command="{Binding SayHelloCommand}"
  10.           Height="30"
  11.           FontSize="14"/>typeof(MyWindow),
  12.   <Button Content="Say Hello"
  13.           Command="{Binding SayHelloCommand}"
  14.           Height="30"
  15.           FontSize="14"/>  <Button Content="Say Hello"
  16.           Command="{Binding SayHelloCommand}"
  17.           Height="30"
  18.           FontSize="14"/>  <Button Content="Say Hello"
  19.           Command="{Binding SayHelloCommand}"
  20.           Height="30"
  21.           FontSize="14"/>new KeyBinding(ApplicationCommands.Save, Key.S, ModifierKeys.Control));
复制代码
现在来看看整体流程:
  1.   <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/>
复制代码
在View中绑定这个命令。
刚开始这个命令不可执行:
3.png

是因为在ViewModel中是这样写的,首先在构造函数中这样写:
  1.   <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/>public ShellViewModel()  <Button Content="Say Hello"
  5.           Command="{Binding SayHelloCommand}"
  6.           Height="30"
  7.           FontSize="14"/>{  <Button Content="Say Hello"
  8.           Command="{Binding SayHelloCommand}"
  9.           Height="30"
  10.           FontSize="14"/>  <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/>  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/>SayHelloCommand = new RelayCommand(  <Button Content="Say Hello"
  17.           Command="{Binding SayHelloCommand}"
  18.           Height="30"
  19.           FontSize="14"/>  <Button Content="Say Hello"
  20.           Command="{Binding SayHelloCommand}"
  21.           Height="30"
  22.           FontSize="14"/>  <Button Content="Say Hello"
  23.           Command="{Binding SayHelloCommand}"
  24.           Height="30"
  25.           FontSize="14"/>  <Button Content="Say Hello"
  26.           Command="{Binding SayHelloCommand}"
  27.           Height="30"
  28.           FontSize="14"/>  <Button Content="Say Hello"
  29.           Command="{Binding SayHelloCommand}"
  30.           Height="30"
  31.           FontSize="14"/>execute: _ => ShowHelloMessage(),  <Button Content="Say Hello"
  32.           Command="{Binding SayHelloCommand}"
  33.           Height="30"
  34.           FontSize="14"/>  <Button Content="Say Hello"
  35.           Command="{Binding SayHelloCommand}"
  36.           Height="30"
  37.           FontSize="14"/>  <Button Content="Say Hello"
  38.           Command="{Binding SayHelloCommand}"
  39.           Height="30"
  40.           FontSize="14"/>  <Button Content="Say Hello"
  41.           Command="{Binding SayHelloCommand}"
  42.           Height="30"
  43.           FontSize="14"/>  <Button Content="Say Hello"
  44.           Command="{Binding SayHelloCommand}"
  45.           Height="30"
  46.           FontSize="14"/>canExecute: _ => CanSayHello  <Button Content="Say Hello"
  47.           Command="{Binding SayHelloCommand}"
  48.           Height="30"
  49.           FontSize="14"/>  <Button Content="Say Hello"
  50.           Command="{Binding SayHelloCommand}"
  51.           Height="30"
  52.           FontSize="14"/>  <Button Content="Say Hello"
  53.           Command="{Binding SayHelloCommand}"
  54.           Height="30"
  55.           FontSize="14"/>);  <Button Content="Say Hello"
  56.           Command="{Binding SayHelloCommand}"
  57.           Height="30"
  58.           FontSize="14"/>}
复制代码
其中控制是否能执行的,设置了一个属性来管理:
  1. public bool CanSayHello => !string.IsNullOrEmpty(Name);
复制代码
命令执行的方法为:
  1.   <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/>private void ShowHelloMessage()  <Button Content="Say Hello"
  5.           Command="{Binding SayHelloCommand}"
  6.           Height="30"
  7.           FontSize="14"/>{  <Button Content="Say Hello"
  8.           Command="{Binding SayHelloCommand}"
  9.           Height="30"
  10.           FontSize="14"/>  <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/>  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/>MessageBox.Show($"Hello, {Name}", "Hello, Native WPF", MessageBoxButton.OK, MessageBoxImage.Information);  <Button Content="Say Hello"
  17.           Command="{Binding SayHelloCommand}"
  18.           Height="30"
  19.           FontSize="14"/>}
复制代码
刚开始Name属性为空,所以CanSayHello为false,所以命令不能执行。
为什么输入东西就可以变成执行了呢?
  1. public string Name {  <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/>  <Button Content="Say Hello"
  5.           Command="{Binding SayHelloCommand}"
  6.           Height="30"
  7.           FontSize="14"/> get => _name;  <Button Content="Say Hello"
  8.           Command="{Binding SayHelloCommand}"
  9.           Height="30"
  10.           FontSize="14"/>  <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/> set  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/>  <Button Content="Say Hello"
  17.           Command="{Binding SayHelloCommand}"
  18.           Height="30"
  19.           FontSize="14"/> {  <Button Content="Say Hello"
  20.           Command="{Binding SayHelloCommand}"
  21.           Height="30"
  22.           FontSize="14"/>  <Button Content="Say Hello"
  23.           Command="{Binding SayHelloCommand}"
  24.           Height="30"
  25.           FontSize="14"/>  <Button Content="Say Hello"
  26.           Command="{Binding SayHelloCommand}"
  27.           Height="30"
  28.           FontSize="14"/>  <Button Content="Say Hello"
  29.           Command="{Binding SayHelloCommand}"
  30.           Height="30"
  31.           FontSize="14"/> if (SetProperty(ref _name, value))  <Button Content="Say Hello"
  32.           Command="{Binding SayHelloCommand}"
  33.           Height="30"
  34.           FontSize="14"/>  <Button Content="Say Hello"
  35.           Command="{Binding SayHelloCommand}"
  36.           Height="30"
  37.           FontSize="14"/>  <Button Content="Say Hello"
  38.           Command="{Binding SayHelloCommand}"
  39.           Height="30"
  40.           FontSize="14"/>  <Button Content="Say Hello"
  41.           Command="{Binding SayHelloCommand}"
  42.           Height="30"
  43.           FontSize="14"/> {  <Button Content="Say Hello"
  44.           Command="{Binding SayHelloCommand}"
  45.           Height="30"
  46.           FontSize="14"/>  <Button Content="Say Hello"
  47.           Command="{Binding SayHelloCommand}"
  48.           Height="30"
  49.           FontSize="14"/>  <Button Content="Say Hello"
  50.           Command="{Binding SayHelloCommand}"
  51.           Height="30"
  52.           FontSize="14"/>  <Button Content="Say Hello"
  53.           Command="{Binding SayHelloCommand}"
  54.           Height="30"
  55.           FontSize="14"/>  <Button Content="Say Hello"
  56.           Command="{Binding SayHelloCommand}"
  57.           Height="30"
  58.           FontSize="14"/>  <Button Content="Say Hello"
  59.           Command="{Binding SayHelloCommand}"
  60.           Height="30"
  61.           FontSize="14"/> ((RelayCommand)SayHelloCommand).RaiseCanExecuteChanged();  <Button Content="Say Hello"
  62.           Command="{Binding SayHelloCommand}"
  63.           Height="30"
  64.           FontSize="14"/>  <Button Content="Say Hello"
  65.           Command="{Binding SayHelloCommand}"
  66.           Height="30"
  67.           FontSize="14"/>  <Button Content="Say Hello"
  68.           Command="{Binding SayHelloCommand}"
  69.           Height="30"
  70.           FontSize="14"/>  <Button Content="Say Hello"
  71.           Command="{Binding SayHelloCommand}"
  72.           Height="30"
  73.           FontSize="14"/> }  <Button Content="Say Hello"
  74.           Command="{Binding SayHelloCommand}"
  75.           Height="30"
  76.           FontSize="14"/>  <Button Content="Say Hello"
  77.           Command="{Binding SayHelloCommand}"
  78.           Height="30"
  79.           FontSize="14"/> } }
复制代码
在RelayCommand中有一个RaiseCanExecuteChanged方法:
  1.   <Button Content="Say Hello"
  2.           Command="{Binding SayHelloCommand}"
  3.           Height="30"
  4.           FontSize="14"/> public void RaiseCanExecuteChanged()  <Button Content="Say Hello"
  5.           Command="{Binding SayHelloCommand}"
  6.           Height="30"
  7.           FontSize="14"/> {  <Button Content="Say Hello"
  8.           Command="{Binding SayHelloCommand}"
  9.           Height="30"
  10.           FontSize="14"/>  <Button Content="Say Hello"
  11.           Command="{Binding SayHelloCommand}"
  12.           Height="30"
  13.           FontSize="14"/>  <Button Content="Say Hello"
  14.           Command="{Binding SayHelloCommand}"
  15.           Height="30"
  16.           FontSize="14"/> CommandManager.InvalidateRequerySuggested();  <Button Content="Say Hello"
  17.           Command="{Binding SayHelloCommand}"
  18.           Height="30"
  19.           FontSize="14"/> }
复制代码
CommandManager.InvalidateRequerySuggested(); 是 WPF 中用于强制刷新命令的可执行状态的方法。所有绑定了ICommand的控件(如 Button、MenuItem 等)马上重新评估自己的 CanExecute 状态。
然后因为Name不为空,CanSayHello为True,这个命令就可以执行了。
点击按钮就会触发RelayCommand中的Execute方法:
4.png

在ViewModel的构造函数中。实例化了一个RelayCommand对象,并且将_ => ShowHelloMessage()这个委托赋值给了execute,所以触发命令之后就会执行ShowHelloMessage方法。
5.png

以上就是使用WPF原生的方法实现的一个使用命令的例子。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册