说不尽的MVVM(4) – 发号施令的Command

知识预备

阅读本文,我假定你具备以下知识:

  • C# WPF基础知识
  • 知道WPF的命令

WPF相对WinForm加了一种Command的机制,对用户的操作进行更加灵活的处理,相信很多朋友知道并用过Routed Command,但这不是本文讨论的重点,本文主要讨论在MVVM模式中,用户输入与后台数据的交互所用的Command。

ICommand接口

在WPF中,所有的命令都是基于ICommand接口的,ICommand的接口有三个成员

Execute 方法

说不尽的MVVM(4) – 发号施令的Command

这个方法,顾名思义,是在Command被触发时要执行的操作,parameter 是与这个命令绑定相关的Command Parameter

CanExecute 方法

说不尽的MVVM(4) – 发号施令的Command

一个Command不是什么时候都可以执行的,比如在登录时,如果没有填写用户名或密码,点击登录按钮是没有意义的,这时应该把Command禁用,在Command Execute之前,命令系统会调用这个方法判断这个命令是否可用。

CanExecuteChanged 事件

说不尽的MVVM(4) – 发号施令的Command

当命令的可用状态(availability)发生改变时,比如上面的例子,用户输入了用户名和密码,我们可以通过这个事件通知命令系统,命令系统会重新调用CanExecute方法,更新命令绑定的状态。

RelayCommand

名字由来

和WPF自带的Routed Command不同,在MVVM模式中,当Command把用户的操作传递到ViewModel后,也就完成了他的使命了,因此,我们会在ViewModel中把一个方法和Command关联起来,Command的任务是去调用方法,在这种情况下,Command起着一个中继的作用,RelayCommand这个名字就是这么来的,在Prism 里面,又叫DelegatedCommand。

实现RelayCommand

虽然MVVM Light 里面已经有了一个RelayCommand,但为了了解他的原理,最好的方法就是自己实现一个。

说不尽的MVVM(4) – 发号施令的Command

首先我们需要一个接收一个object的Action,用于存放Execute时执行的操作

说不尽的MVVM(4) – 发号施令的Command

然后我们需要一个接收一个object,返回值为bool的Func,用于存放CanExecute判断的操作

说不尽的MVVM(4) – 发号施令的Command

Command的CanExecute里面,写这样的代码

说不尽的MVVM(4) – 发号施令的Command

在Command的Execute里面,执行Execute

说不尽的MVVM(4) – 发号施令的Command

然后我们在提供一个方法,用于在命令状态改变时触发 CanExecuteChanged 事件

到此为止,我们已经实现了一个很简陋的RelayCommand,这个Command用于生产环境中时很危险的,但对于我们理解他的原理,已经足够了。

Command Binding 和 Command Parameter

对于Command的绑定非常简单,只需要想数据绑定那样把ViewModel里面的Command绑定到控件的Command属性上就可以了,在这里提一个小建议:在ViewModel中对外暴露的属性用ICommand类型,属性的后台字段用实际的Commad类型,就像这样

说不尽的MVVM(4) – 发号施令的Command

因为Command binding需要的只是一个ICommand接口,因此我们不需要对外暴露过多的信息。

上面我们看到,ICommand的Execute和CanExecute方法都有一个object类型的参数,这个参数便是Command Parameter,在绑定命令的时候,可以从控件的CommandParameter属性指定,在CommandParameter更新的时候,Comman的CanExecute会被重新执行(有一些小问题,稍后讲述)

神器Blend SDK

需求是不断变化的,如果哪天我们不是要在按钮被单击时执行操作而是在鼠标移过是执行操作,那WPF自带的Command binding就无能为力了。这时我们就要请出我们的大神——Blend SDK,这里我回答的一个博问作为实例

说不尽的MVVM(4) – 发号施令的Command

Windows Phone 的 AppBar

在Windows Phone的开发中,由于App bar是系统部分,不是依赖对象,无法对其Command进行数据绑定,非常不方便。

在这里推荐Allen Lee开发的 AppBarUtils (http://appbarutils.codeplex.com/ ),适用于WP7和WP8,关于这个类库的使用,他的博客有非常详细的教程,这里不再阐述。

你可能会有的疑问

Command parameter 更新时Command状态不改变是怎么回事?

在用MVVM Light时,我发现在非UI线程更新command parameter 时,命令的更新不正确 ,而且我分别在WPF、Sliverlight、WinRT上进行实验,得到三种不同的结果,具体原因我不太说的清,最好的解决办法是使用Dispatcher Helper回到UI线程去更新,用法请看本系列第二篇文章
说不尽的MVVM(4) – 发号施令的Command

上一篇:android 5.0 创建多用户 双开多开应用(2)


下一篇:MDK st-link下载STM32程序出现Internal command error和Error:Flash download failed. Target DLL