在上一节的MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新。但是这并不是我们使用MVVM的正确方式。MVVM的目的是为了最大限度地降低了Xaml文件和CS文件的耦合度,分离界面和业务逻辑,所以我们要通过命令(Command)的来将Button的事件分离出来。
因为本文中需要使用Command命令,我们先来简单了解Command命令。在WPF中使用命令的步骤很简单
WPF中命令的核心是System.Windows.Input.ICommand接口,所有命令对象都实现了此接口。当创建自己的命令时,不能直接实现ICommand接口,而是要使用System.Windows.Input.RouteCommand类,该类已经实现了ICommand接口,所有WPF命令都是RouteCommand类的实例。在程序中处理的大部分命令不是RoutedCommand对象,而是RoutedUICommand类的实例,它继承自RouteCommand类。
WPF提供了一个很好的方式来解决事件绑定的问题ICommand。很多控件都有Command属性,如果没有,我们可以将命令绑定到触发器上。接下来我们来先实现一个ICommand接口。ICommand需要用户定义两个方法bool CanExecute和void Execute。第一个方法可以让我们来判断是否可以执行这个命令,第二个方法就是我们具体的命令。
1、在项目中创建一个文件夹common,再添加一个类RelayCommand,这个类就是命令执行的代理类,完整代码是:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace WpfApp6.common
{
/// <summary>
/// 代理命令类
/// </summary>
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
/// <summary>
/// 要执行的操作
/// </summary>
private Action<object> executeActions;
/// <summary>
/// 是否可以执行的委托
/// </summary>
private Func<object, bool> canExecuteFunc;
/// <summary>
/// 构造函数 无参构造
/// </summary>
public RelayCommand() { }
/// <summary>
/// 通过执行的委托构造
/// </summary>
/// <param name="execute"></param>
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
/// <summary>
/// 通过执行的操作与是否可执行的委托
/// </summary>
/// <param name="execute">要执行的操作</param>
/// <param name="canExecute">是否可以被执行</param>
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.executeActions = execute;
this.canExecuteFunc = canExecute;
}
/// <summary>
/// 命令是否可以执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
if (canExecuteFunc != null)
{
return this.canExecuteFunc(parameter);
}
else
{
return true;
}
}
/// <summary>
/// 要执行的操作
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (executeActions == null)
{
return;
}
this.executeActions(parameter);
}
/// <summary>
/// 执行CanExecuteChanged事件
/// </summary>
public void OnCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, new EventArgs());
}
}
}
2、在上节代码的基础上,界面上添加一个按钮,如图:
3、修改EmpViewModel2.cs,在里面增加代码:
4、运行程序,效果如下:
对于 ICommand 的一些理解:
在笔者看来,ICommand 就是对函数的一种封装。只是在调用这个函数前,必须进行一个可执行判定。
比如,在假期中使用滴滴打车。
执行参数:打车距离
执行函数:将乘客送到目的地。
可执行条件:打车距离必须大于5公里,才会有司机接单。
上述看法,只是单独从接口本来而言。
WPF 中为什么要定义 ICommand ?在 WPF 中定义这样一个接口的目的是为了实现 MVVM 的框架设计,换一种的说法就是为了解耦。
小结:ICommand 是 MVVM 的核心组件。 ICommand 在 MVVM 中经常使用,它提供了View和ViewModel(用户界面和业务逻辑)之间的分离逻辑。 XAML 提供了一种通过 ICommand 更好地绑定 GUI 事件的方法。 ICommand 要求用户定义两个方法,bool CanExecute 和 void Execute。 CanExecute 方法只是告诉用户,我可以执行这个 Action 吗? 这对于控制 GUI 元素的可操作性非常有用。
ICommand 非常简单,但是也可以完在更加有趣和复杂的功能。 ICommand 将用户界面集成到业务逻辑中,或者在视图与视图模型之间进行直接通信。 它还为视图提供了更新模型/视图模型的机制。
这一波操作,又成功了。后面继续精彩人生。