天天看点

【wpf】Command Binding 命令绑定的使用前言Command BindingCommandManager强制触发鼠标和键盘

前言

这次讲解的命令绑定,主要解决的问题是,为实现MVVM模式进行铺垫,实现前后台逻辑的解耦。

我们知道如果Button直接实现Click事件,那么实现的逻辑必然在Window后台代码中,为了实现MVVM,我要将业务逻辑放在ViewMode里面,这时需要Command Binding。

Command Binding

使用Command 替换 Click

前台代码:

<Button Grid.Row="2"  
    Command="{Binding BtnSaveCommand}"
    CommandParameter="{Binding RelativeSource={RelativeSource Self}}">保存</Button>
           

创建CommandBase类

然后创建CommandBase类,该类实现ICommand接口。

ICommand需要实现一个事件:CanExecuteChanged

两个方法: Execute, CanExecute

Execute 是命令促发后,系统会调用的回调函数

CanExecute 是当CanExecuteChanged事件触发后,体统会调用它,并更具它的返回值判断控件是否可用。

public class CommandBase : ICommand
{
    public event EventHandler CanExecuteChanged;
    public Action<object> DoExecute { get; set; }
    
    // 这里给个默认的值,不实现就返回true
    public Func<object, bool> DoCanExecute { get; set; } = new Func<object, bool>(obj => true);

    public bool CanExecute(object parameter)
    {
        // 让实例去实现这个委托
        return DoCanExecute?.Invoke(parameter) == true;// 绑定的对象 可用
    }

    public void Execute(object parameter)
    {
        // 让实例去实现这个委托
        DoExecute?.Invoke(parameter);
    }


    //目的 就是触发一次CanExecuteChanged事件   
    public void DoCanExecuteChanged()
    {
        // 触发事件的目的就是重新调用CanExecute方法
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}
           

ViewMode中实例化命令

public CommandBase BtnSaveCommand { get; set; }

public ConfigInfoViewMode()
{

    BtnSaveCommand = new CommandBase()
    {
        DoExecute = new Action<object>(SaveTo),
        DoCanExecute = new Func<object, bool>(CanSave)
    };
}

//最终按钮会触发到改函数
void Save(object obj)
{
    
}

//决定按键是否可用(这也是命令额外的一个作用)
// 通过调用DoCanExecuteChanged,可以触发该元素
public bool CanSave(object obj)
{
    return true;
}
           

事件触发

//目的 就是触发一次CanExecuteChanged事件   
    public void DoCanExecuteChanged()
    {
        // 触发事件的目的就是重新调用CanExecute方法
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
           

触发事件的目的就是重新调用CanExecute方法,从而从新判断控件是否可用。

但是这个DoCanExecuteChanged(),是需要我们人为调用的。

CommandManager

如果不想手动调用DoCanExecuteChanged(),还有一个办法就是CommandManager。

另外一种写法可以让系统去调用,我们需要一个新的知识点CommandManager

以下两种写法都可以,只需要在定义CanExecuteChanged时稍微改动一下:

// 通知:当前按钮检查可用条件     触发 一次CanExecute
// 写法一
public event EventHandler? CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}

//写法二
public event EventHandler? CanExecuteChanged
{
    add => CommandManager.RequerySuggested += value; 
    remove => CommandManager.RequerySuggested -= value; 
}
           

这里的意思是,通过静态变量CommandManager将CanExecuteChanged挂载到,RequerySuggested 这个事件上,这里的value是指CanExecuteChanged本身,下图可以证明。(这个和属性的value有着异曲同工之妙)

【wpf】Command Binding 命令绑定的使用前言Command BindingCommandManager强制触发鼠标和键盘

 从此之后,这个检测调用的工作交给系统。

【wpf】Command Binding 命令绑定的使用前言Command BindingCommandManager强制触发鼠标和键盘

我发现这个检测的时机其实和绑定有关。

<TextBox Text="{Binding mainModel.Value1,UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding mainModel.Value3}"/>
           

我们在检擦函数中这么写的:

// Hello命令的的可用判断逻辑
public bool CanHello(object obj)
{
    // 命令可用条件
    // 当调用 CanExecuteChanged  事件后,重新进行条件检查
    return this.mainModel.Value1 != 0;
}


public bool CanWorld(object obj)
{
    return this.mainModel.Value3 != 0;
}
           

也就是说,TextBox中的值会决定Button是否可用!

那么第一个TextBox的值,只要一发生改变,那么就会触发检查是否可用,而第二个TextBox只有

失去焦点的时候,才会触发检查。

这里有个小疑问,我们的Command是写在Button上的,所以判断是Button是否可用,同时Command实现了CanExecuteChanged事件,并挂载到了全局,以便系统调用,那系统是怎么知道

变化的Value和Button的关系的呢?也不知道微软是什么时候将这个指和Button关联上的。

强制触发

当然,此时如果你觉得你想在某个时刻进行强制触发检测,也是可以的,还是使用CommandManager这个静态变量:

CommandManager.InvalidateRequerySuggested();
           

鼠标和键盘

写道这里,其实还存在一个问题,Button的Command是由但是触发的,如果我想通过双击或者快捷键触发怎么办呢?

InputBindings

InputBindings,满足你的需求:

<Button Content="Button">
    <Button.InputBindings>
        <MouseBinding MouseAction="LeftDoubleClick"
                      Command="{Binding Btn1Command}"
                      CommandParameter="123"/>
        <KeyBinding Key="Q" Modifiers="Alt"
                    Command="{Binding Btn1Command}"
                    CommandParameter="123"/>
    </Button.InputBindings>
</Button>
           

MouseBinding 中的MouseAction还有如下操作: 

  • 单击鼠标左键 :LeftClick
  • 双击鼠标左键:LeftDoubleClick
  • 单击鼠标中键 :MiddleClick
  • 双击鼠标中键:MiddleDoubleClick
  • 单击鼠标右键:RightClick
  • 双击鼠标右键:RightDoubleClick
  • 不执行任何操作:None
  • 旋转鼠标滚轮:WheelClick

KeyBinding 

KeyBinding 可以帮我们实现快捷键和快捷键组合,简直完美~~。

继续阅读