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

发布于:2025-07-08 ⋅ 阅读:(15) ⋅ 点赞:(0)


一、命令

在这里插入图片描述
官方文档: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. 示例

在这里插入图片描述
在这里插入图片描述

    <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禁用按钮
    在这里插入图片描述
<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>
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用法

在这里插入图片描述

    <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文件内自定义命令接口
在这里插入图片描述
在这里插入图片描述

<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>
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的事件解释:
在这里插入图片描述

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


网站公告

今日签到

点亮在社区的每一天
去签到