知识预备

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

  • 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. 特征工程 dataframe格式

    import os import copy import codecs import operator import re from math import log from pyspark.sql ...

  2. anomaly detection algorithm

    anomaly detection algorithm 以上就是异常监测算法流程

  3. 解决C# 转到定义时打开的是元数据文件而非源代码文件的问题

    原因:添加引用时 使用的是“浏览"选项卡,选择了项目生成的dll作为引用的内容. 解决:添加引用时 使用的是"项目"选项卡,选择了项目本身作为引用的内容.

  4. poj 2891 Strange Way to Express Integers (非互质的中国剩余定理)

    Strange Way to Express Integers Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 9472   ...

  5. golang--gopher北京大会(1)

    大会感想:牛人真的很能写代码,实现很多功能,而且开源的精品越多,影响力越大,越能过上dream life.比如beego的作者,去了America,进入了Apple.另外,精英们特点是表达能力很强,也 ...

  6. 理解GC日志

    每一种收集器的日志形式都是由它们自身的实现所决定的,换而言之,每个收集器的日志格式都可以不一样.但虚拟机设计者为了方便用户阅读,将各个收集器的日志都维持一定的共性,例如以下两段典型的GC日志: 33. ...

  7. LightOJ 1094 - Farthest Nodes in a Tree(树的直径)

    http://acm.hust.edu.cn/vjudge/contest/121398#problem/H 不是特别理解,今天第一次碰到这种问题.给个链接看大神的解释吧 http://www.cnb ...

  8. 使用Dapper时,如何将MySqlParameters[] 变成Dapper.DynamicParameters动态对象

    在开发过程中,如何替原生的参数化MySqlParameters[]换成Dpapper的参数化DynamicParameters对象正确的做法:var args = new DynamicParamet ...

  9. 对CLR基本原理概念&垃圾回收机制的简单理解

    前言,之前有说过C语言的函数&变量的一些基本概念,说得可能不是很好,先也把C#的.里相关的也说下,已成一统. 而说函数变量,其实主要就是GC,而GC又是CLR的主要内容,故就有了此文. CLR ...

  10. MapReduce几个简单的例子

    文件合并和去重: 可以把每一行文本作为key,value为随意值. 数字排序: MapReduce过程中就有排序,它是按照key值进行排序的,如果key为封装int的IntWritable类型,那么M ...