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

相关推荐
没有bug.的程序员2 天前
SOA、微服务、分布式系统的区别与联系
java·jvm·微服务·架构·wpf·日志·gc
Macbethad2 天前
基于WPF的半导体设备配方管理程序技术方案
wpf
FuckPatience2 天前
WPF Geometry
wpf
武藤一雄3 天前
.NET 中常见计时器大全
microsoft·微软·c#·.net·wpf·.netcore
MarkHD3 天前
车辆TBOX科普 第70次 AUTOSAR Adaptive、容器化与云原生的融合革命
云原生·wpf
极客智造3 天前
WPF Behavior 实战:自定义 InvokeCommandAction 实现事件与命令解耦
wpf
L、2183 天前
Flutter 与 OpenHarmony 深度集成:构建分布式多端协同应用
分布式·flutter·wpf
布伦鸽3 天前
C# WPF -MaterialDesignTheme 找不到资源“xxx“问题记录
开发语言·c#·wpf
小二·4 天前
MyBatis基础入门《十五》分布式事务实战:Seata + MyBatis 实现跨服务数据一致性
分布式·wpf·mybatis
helloworddm4 天前
UnregisterManyAsync
wpf