说不尽的MVVM(4) – 发号施令的Command
知识预备
阅读本文,我假定你具备以下知识:
- C# WPF基础知识
- 知道WPF的命令
WPF相对WinForm加了一种Command的机制,对用户的操作进行更加灵活的处理,相信很多朋友知道并用过Routed Command,但这不是本文讨论的重点,本文主要讨论在MVVM模式中,用户输入与后台数据的交互所用的Command。
ICommand接口
在WPF中,所有的命令都是基于ICommand接口的,ICommand的接口有三个成员
Execute 方法

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

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

当命令的可用状态(availability)发生改变时,比如上面的例子,用户输入了用户名和密码,我们可以通过这个事件通知命令系统,命令系统会重新调用CanExecute方法,更新命令绑定的状态。
RelayCommand
名字由来
和WPF自带的Routed Command不同,在MVVM模式中,当Command把用户的操作传递到ViewModel后,也就完成了他的使命了,因此,我们会在ViewModel中把一个方法和Command关联起来,Command的任务是去调用方法,在这种情况下,Command起着一个中继的作用,RelayCommand这个名字就是这么来的,在Prism 里面,又叫DelegatedCommand。
实现RelayCommand
虽然MVVM Light 里面已经有了一个RelayCommand,但为了了解他的原理,最好的方法就是自己实现一个。

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

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

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

在Command的Execute里面,执行Execute

然后我们在提供一个方法,用于在命令状态改变时触发 CanExecuteChanged 事件
到此为止,我们已经实现了一个很简陋的RelayCommand,这个Command用于生产环境中时很危险的,但对于我们理解他的原理,已经足够了。
Command Binding 和 Command Parameter
对于Command的绑定非常简单,只需要想数据绑定那样把ViewModel里面的Command绑定到控件的Command属性上就可以了,在这里提一个小建议:在ViewModel中对外暴露的属性用ICommand类型,属性的后台字段用实际的Commad类型,就像这样

因为Command binding需要的只是一个ICommand接口,因此我们不需要对外暴露过多的信息。
上面我们看到,ICommand的Execute和CanExecute方法都有一个object类型的参数,这个参数便是Command Parameter,在绑定命令的时候,可以从控件的CommandParameter属性指定,在CommandParameter更新的时候,Comman的CanExecute会被重新执行(有一些小问题,稍后讲述)
神器Blend SDK
需求是不断变化的,如果哪天我们不是要在按钮被单击时执行操作而是在鼠标移过是执行操作,那WPF自带的Command binding就无能为力了。这时我们就要请出我们的大神——Blend SDK,这里我回答的一个博问作为实例

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的更多相关文章
- 说不尽的MVVM(1) – Why MVVM
最近学的一篇课文<说不尽的狗>竟让我有了写<说不尽的MVVM>这一想法,事非亵渎,实出无奈.我在刚学WPF不久时听说有MVVM这种东西,做了下尝试,发现他能给程序的设计带来很大 ...
- WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参
原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...
- 说不尽的MVVM(2) – MVVM初体验
知识预备 阅读本文,我假定你已经具备以下知识: C#.WPF基础知识 了解Lambda表达式和TPL 对事件驱动模型的了解 知道ICommand接口 发生了什么 某程序员接到一个需求,编写一个媒体渲染 ...
- 从PRISM开始学WPF(六)MVVM(二)Command?
从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...
- WPF学习08:MVVM 预备知识之COMMAND
WPF内建的COMMAND是GOF 提出的23种设计模式中,命令模式的实现. 本文是WPF学习07:MVVM 预备知识之数据绑定的后续,将说明实现COMMAND的三个重点:ICommand Comm ...
- 说不尽的MVVM(5) - 消息满天飞
知识预备 阅读本文,我假定你具备以下知识: C#和WPF基础知识 Lambda表达式 清楚ViewModel的职责 如果我们的程序需要弹出一个MessageBox,我们应该怎么做? 我见过不少人在Vi ...
- 说不尽的MVVM(3) – 从通知属性说起
上篇我们体验了一个从事件处理程序到MVVM程序的转变,在最后也留下了一个问题:RaisePropertyChanged的原理是什么?今天我们来一探究竟. 通过上节做的小例子我们知道,仅仅修改ViewM ...
- MVVM中轻松实现Command绑定(三)任意事件的Command
WPF中不是所有的控件都有Command属性的,如果窗体我需要在ViewModel中处理Loaded事件命令,或者其他事件的命令时,很难都过绑定Command完成,必须要注册依赖属性或事件等,太麻烦了 ...
- MVVM中轻松实现Command绑定任意事件的Command
下面是“银光中国”(不错的WPF或SL网站)WPF学习教程中的一个连接, http://www.silverlightchina.net/html/study/WPF/2011/0715/9034.h ...
随机推荐
- Android Studio鼠标悬停显示注释
Android Studio鼠标悬停显示注释 在AS中配置 如果你想从网上查看注释,到这一步就操作完成. 下面说明让软件使用本地注释: 使用本地注释 以Windows为例: 找到下面文件 C:\Use ...
- 安卓手机开机开启指定Activity
1.布局 默认helloworld布局 2.class BootCompleteReceiver package lpc.com.project522; import android.content. ...
- POJ 3281 Dining
Dining Description Cows are such finicky eaters. Each cow has a preference for certain foods and dri ...
- 打开div层
$('#moneyWin').dialog('open').dialog('center').dialog('setTitle', '用户充值');
- PHP 常用字符串函数整理
PHP语言中的字符串函数也是一个比较易懂的知识.今天我们就为大家总结了将近12种PHP字符串函数,希望对又需要的朋友有所帮助,增加读者朋友的PHP知识库. 1.查找字符位置函数 strpos($str ...
- 第六周PSP
[week6]psp 工作周期:10.20-10.27 本周PSP C类型 C内容 S开始时间 ST结束时间 I中断时间 T净时间(分) 活动 开事后诸葛亮会议 13:00 14:00 0 ...
- 循环不变量loop invariant 与 算法的正确性
在论述插入排序的正确性的时候, 书中引入了循环不变量的概念, 刚开始稍微有点不太明白, 早上查了一波资料之后决定把自己的理解记录下来. 什么是循环不变量 ? 在我看来, 所谓循环不变量的就是一个在循环 ...
- 自已实现的async 只实现了一部分功能
不得不说,人和人的技术确实有差距,同样的功能,其他人就是有办写写的更优雅性能更好 不论是C还是js 自已有功能但看着也比人家的丑好多. //最终效果 同async //目前实现了个人最常用的 seri ...
- 11 个 Linux 上最佳的图形化 Git 客户端
Git是软件开发和若干其他版本控制任务免费和开源的分布式版本控制系统.它被设计用来以应付一切从小到非常大的项目,基于速度,效率和数据完整性. Linux用户主要通过命令行管理Git,不过,一些图形用户 ...
- 云计算和大数据时代网络技术揭秘(十二)自定义网络SDN
软件定义网络——SDN SDN是网络技术热点,即软件定义网络,OpenFlow是实现SDN思想的一个框架标准, open是指公开.开放,具体为控制平面的规则由各个通信厂家自定义变为公开的技术标准, f ...