知识预备

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

  • 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的更多相关文章

  1. 说不尽的MVVM(1) – Why MVVM

    最近学的一篇课文<说不尽的狗>竟让我有了写<说不尽的MVVM>这一想法,事非亵渎,实出无奈.我在刚学WPF不久时听说有MVVM这种东西,做了下尝试,发现他能给程序的设计带来很大 ...

  2. WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参

    原文:WPF ContextMenu 在MVVM模式中绑定 Command及使用CommandParameter传参 ContextMenu无论定义在.cs或.xaml文件中,都不继承父级的DataC ...

  3. 说不尽的MVVM(2) – MVVM初体验

    知识预备 阅读本文,我假定你已经具备以下知识: C#.WPF基础知识 了解Lambda表达式和TPL 对事件驱动模型的了解 知道ICommand接口 发生了什么 某程序员接到一个需求,编写一个媒体渲染 ...

  4. 从PRISM开始学WPF(六)MVVM(二)Command?

    从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...

  5. WPF学习08:MVVM 预备知识之COMMAND

    WPF内建的COMMAND是GOF 提出的23种设计模式中,命令模式的实现. 本文是WPF学习07:MVVM 预备知识之数据绑定的后续,将说明实现COMMAND的三个重点:ICommand  Comm ...

  6. 说不尽的MVVM(5) - 消息满天飞

    知识预备 阅读本文,我假定你具备以下知识: C#和WPF基础知识 Lambda表达式 清楚ViewModel的职责 如果我们的程序需要弹出一个MessageBox,我们应该怎么做? 我见过不少人在Vi ...

  7. 说不尽的MVVM(3) – 从通知属性说起

    上篇我们体验了一个从事件处理程序到MVVM程序的转变,在最后也留下了一个问题:RaisePropertyChanged的原理是什么?今天我们来一探究竟. 通过上节做的小例子我们知道,仅仅修改ViewM ...

  8. MVVM中轻松实现Command绑定(三)任意事件的Command

    WPF中不是所有的控件都有Command属性的,如果窗体我需要在ViewModel中处理Loaded事件命令,或者其他事件的命令时,很难都过绑定Command完成,必须要注册依赖属性或事件等,太麻烦了 ...

  9. MVVM中轻松实现Command绑定任意事件的Command

    下面是“银光中国”(不错的WPF或SL网站)WPF学习教程中的一个连接, http://www.silverlightchina.net/html/study/WPF/2011/0715/9034.h ...

随机推荐

  1. 2016 ICPC北京站现场赛总结(再度流水账)

    其他的都先不说,北大的未名湖真的美! 虽然感觉北大其他地方都有些破旧之感,但是未名湖附近真的值得称赞. 在去北京之前就听说北京温度很低,不过是干冷,果不其然.北京不冷,就是嘴唇太干了,不喝水真的受不了 ...

  2. 在eclipse之中使用Junit

    使用Junit单位测试,能够一定程度上减小项目bug的产生.很多时候,我们都是在main函数里面单独去测试一个方法,这样的测试非常不方便.使用Junit可以是测试单位和项目代码分离,一次性测试多个方法 ...

  3. 2015年毕业生收到的offer和薪资透露

    个人情况:全国排名70多的大学,非211,计算机专业硕士 收到的offer: 苏州同程旅游--6k/月 ,自己要了这么多,就给了这么多,没有规范.苏州蜗牛科技--8k/月 ,给了个口头offer,要去 ...

  4. performSelector may cause a leak because its selector is unknown解决

    解决方法 SEL selector = NSSelectorFromString(@"applySketchFilter:"); IMP imp = [FWApplyFilter ...

  5. Elasticsearch refresh vs. flush【转载】

    源地址:    http://www.jianshu.com/p/0e9f6346f1fe 问: 若一个新的文档索引进ES索引,则它在索引操作执行后约1s可以搜索到.然而我们可以直接调用_flush或 ...

  6. Python全栈--7.3--模块补充configparser--logging--subprocess--os.system--shutil

    模块补充: 一.configparser用于处理特定格式的文件,其本质是利用open来操作文件 继承到2版本 configparser 实现了更多智能特征,更有壳预见性,新的应用更偏好这个版本, 处理 ...

  7. 爬虫---request+++urllib

    网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另外一些不常使用的名字还有蚂蚁.自动索引.模拟程序或者蠕 ...

  8. AngularJS学习--- 过滤器(filter),格式化要显示的数据 step 9

    1.切换目录,启动项目 git checkout step- npm start 2.需求: 格式化要显示的数据. 比如要将true-->yes,false-->no,这样相互替换. 3. ...

  9. 常见的HTTP 状态代码

    HTTP 状态代码 如果向您的服务器发出了某项请求要求显示您网站上的某个网页(例如,当用户通过浏览器访问您的网页或在 Googlebot 抓取该网页时),那么,您的服务器会返回 HTTP 状态代码以响 ...

  10. flash网页播放器

    http://www.52player.com/VideoPlayer/  下载