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

相关推荐
SEO-狼术2 天前
DevExpress WPF Crack, DevExpress WPF v25.1
wpf
小老鼠爱大米2 天前
C# WPF - Prism 学习篇:搭建项目(一)
c#·wpf·prism
博睿谷IT99_2 天前
Hadoop 分布式存储与计算框架详解
wpf
qq_392397123 天前
Redis常用操作
数据库·redis·wpf
三千道应用题3 天前
WPF学习笔记(25)MVVM框架与项目实例
wpf
厦门德仔4 天前
【WPF】WPF(样式)
android·java·wpf
三千道应用题5 天前
WPF学习笔记(16)树控件TreeView与数据模板
wpf
✎ ﹏梦醒͜ღ҉繁华落℘5 天前
WPF学习(四)
学习·wpf
zzyzxb5 天前
WPF中依赖属性和附加属性
wpf