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

相关推荐
Scout-leaf3 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
柒.梧.5 天前
基于SpringBoot+JWT 实现Token登录认证与登录人信息查询
wpf
十月南城8 天前
Flink实时计算心智模型——流、窗口、水位线、状态与Checkpoint的协作
大数据·flink·wpf
听麟11 天前
HarmonyOS 6.0+ 跨端会议助手APP开发实战:多设备接续与智能纪要全流程落地
分布式·深度学习·华为·区块链·wpf·harmonyos
@hdd11 天前
Kubernetes 可观测性:Prometheus 监控、日志采集与告警
云原生·kubernetes·wpf·prometheus
zls36536511 天前
C# WPF canvas中绘制缺陷分布map
开发语言·c#·wpf
专注VB编程开发20年11 天前
c#Redis扣款锁的设计,多用户,多台电脑操作
wpf
闲人编程12 天前
定时任务与周期性调度
分布式·python·wpf·调度·cron·定时人物·周期性
zls36536512 天前
C# WPF canvas中绘制缺陷分布map并实现缩放
开发语言·c#·wpf
数据知道13 天前
PostgreSQL:Citus 分布式拓展,水平分片,支持海量数据与高并发
分布式·postgresql·wpf