WPF学习笔记(24)命令与ICommand接口

命令与ICommand接口


一、命令

官方文档:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/commanding-overview

1. ICommandSource

官方文档:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/how-to-implement-icommandsource

2. 示例


xml 复制代码
    <Grid>
        <TextBox x:Name="textBox" Text="TextBox" VerticalAlignment="Top"  Height="150" Margin="219,35,187,0"/>

        <Button x:Name="buttonCut"
                Content="剪切"
                Command="ApplicationCommands.Cut"
                CommandTarget="{Binding ElementName=textBox}"
                Height="100" Margin="219,233,419,102"/>
        <Button x:Name="buttonPaste"
                Content="粘贴"
                Command="ApplicationCommands.Paste"
                CommandTarget="{Binding ElementName=textBox}" Margin="453,233,187,107"/>
    </Grid>

3. CommandBinding


  • 当TEXTBOX内容长度大于0时,CanExecute 被判断为true
  • true可以启用命令源按钮,false禁用按钮
xml 复制代码
<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Cut" CanExecute="my_CanExecute" Executed="my_Execute"/>
</Window.CommandBindings>

<Grid>
    <TextBox x:Name="textBox" Text="TextBox" VerticalAlignment="Top"  Height="150" Margin="219,35,187,0"/>

    <Button x:Name="buttonCut" Margin="219,233,419,102" Height="100" 
            Content="剪切"
            Command="ApplicationCommands.Cut"/>
        
    <Button x:Name="buttonPaste"
            Content="粘贴"
            Command="ApplicationCommands.Paste"
            CommandTarget="{Binding ElementName=textBox}"
            Margin="453,233,187,107"/>
</Grid>
csharp 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void my_Execute(object sender, ExecutedRoutedEventArgs e)
    {
        Console.WriteLine("Execute!!!");
        textBox.Cut();
    }

    private void my_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = textBox.SelectionLength > 0;
    }
}

二、ICommand

官方文档:https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.input.icommand?view=net-9.0

1.ICommand接口

ICommand接口的属性与事件如下:

2. ICommand用法

xml 复制代码
    <Grid>
        <TextBox HorizontalAlignment="Left" Margin="222,62,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="422" Height="102"/>
        <Button x:Name="button1" Content="  自定义命令" HorizontalAlignment="Left" Margin="222,217,0,0" VerticalAlignment="Top" Height="64" Width="145"/>
        <Button x:Name="button2" Content="触发事件" HorizontalAlignment="Left" Margin="499,217,0,0" VerticalAlignment="Top" Height="64" Width="145"/>
    </Grid>

在MainWindow.xaml.cs文件内自定义命令接口

xml 复制代码
<Window.Resources>
    <local:MyCommand x:Key="MyCMD" />
</Window.Resources>
<Grid>
    <TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="222,62,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="422" Height="102"/>
    <Button x:Name="button1" Content="  自定义命令"
            Command="{StaticResource MyCMD}"
            CommandParameter="{Binding ElementName=textBox,Path=Text}"
            HorizontalAlignment="Left" Margin="222,217,0,0" VerticalAlignment="Top" Height="64" Width="145"/>
    <Button x:Name="button2" Content="触发事件" HorizontalAlignment="Left" Margin="499,217,0,0" VerticalAlignment="Top" Height="64" Width="145"/>
</Grid>
csharp 复制代码
public class MyCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter)
    {
        
        return true;//按钮可以点击
        //return false;//按钮不可点击
    }
    //Execute方法中实现命令处理逻辑
    public void Execute(object parameter)
    {
        MessageBox.Show(parameter.ToString());
    }
}

以下为CanExecuteChanged的事件解释:

csharp 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        MyCommand c = Resources["MyCMD"] as MyCommand;
        //触发CanExecuteChanged
        c.RaiseCanExecuteChanged();
    }
}
//实现ICommand接口
public class MyCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter)
    {
        String str = parameter as String;
        return str?.Length > 0;
        //return true;//按钮可以点击
        //return false;//按钮不可点击
    }
    //Execute方法中实现命令处理逻辑
    public void Execute(object parameter)
    {
        MessageBox.Show(parameter.ToString());
    }

    //定义一个方法,手动触发CanExecuteChanged事件
    public void RaiseCanExecuteChanged() 
    {
        //表面上,没有为 CanExecuteChanged 这个事件添加任何订阅方法
        //例如CanExecuteChanged += fun;
        //但是我们为按钮设置命令时,自动加入了一个此事件订阅的方法,
        //并且这个订阅的方法,会去调用命令的CanExecute
        //可通过Delegate查看CanExecuteChanged的来源与内容
        Delegate[] delegates = CanExecuteChanged.GetInvocationList();
		//delegates内查看到 System.Windows.Input.CanExecuteChangedEventManager+HandlerSink"
		//OnCanExecuteChanged
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

3. CanExecute

以ButtonBase为例介绍,调用了OnCommandChanged

OnCommandChanged调用了HookCommand

HookCommand调用了AddHandler,CanExecute调用了CanExecuteCommandSource

AddHandler调用的PrivateAddHandler又new 了一个HandlerSink

HandlerSink将OnCommandChanged函数添加到Icommand接口的CanExecuteChanged



总结

关于ButtonBase、CanExecuteChangedEventManager、commandHelpers的详细原理、我们可以参考WPF框架的源码
https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/ButtonBase.cs
https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Command/CanExecuteRoutedEventArgs.cs
https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Commands/CommandHelpers.cs

相关推荐
Chris _data15 天前
WPF 学习第三天 — Modbus RTU 串口通信
hadoop·学习·wpf
布吉岛的石头15 天前
Java 程序员第 43 阶段05:微服务整合大模型,跨服务调用架构设计实战,Seata分布式事务实战
wpf
步步为营DotNet15 天前
基于.NET Aspire 实现云原生应用的高效监控与可观测性
云原生·.net·wpf
芒鸽16 天前
HarmonyOS 分布式开发实战:设备协同、数据共享与跨设备迁移
分布式·wpf·harmonyos
Volunteer Technology16 天前
Flink状态管理与容错(二)
大数据·flink·wpf
happyprince17 天前
07_verl-Trainer模块详解
人工智能·架构·wpf·强化学习
bugcome_com17 天前
WPF + Prism 技术指南与实战项目(二、模板搭建)
wpf
小满Autumn17 天前
log4net 日志框架 — 从配置到实战速查手册
笔记·c#·.net·wpf·上位机·log4net
政沅同学18 天前
基于 C# WPF + HALCON 的工业视觉算法工具框架(开源)
开发语言·c#·wpf
happyprince18 天前
03_verl-设计理念与核心原理
wpf