MVVM实践教程

     算算,从事Silverlight和WPF的开发也有1年多的时间了,虽然时间不算长,虽然还没有突出的成就,但是感觉也还算一般。

     但是,从头至今都没有去认真研究和使用过MVVM,虽然它被认为是Silverlight和WPF开发的最佳架构实践。

     我想这里面还是有一些原因,就像一般开始我们始终都不会看好单元测试。直到有一天你体会到它的魅力,它的好处。

     最近的项目,却不得不采用MVVM的模式:UI没有定,甚至服务端的Service都没有定,但是不能等到这些都做好才开始展开我们的开发工作。

     于是,痛下决心研究MVVM的模式,在学习过程中,发现一些问题。MVVM的使用不仅仅是因为它需要新的思维,使View和ViewModel之间的交互变得更麻烦。这其中还有另外的原因,那就是参考资料不全。

     一般网上的资料都是一片简单的教程,大体都是怎么使用命令,怎么使用Binding的方式来建立应用程序。这些几乎都出自John Smith的那篇WPF的文章。

     而实际上,在开发中,还会遇到其他问题,例如页面切换,UI事件,并且简单的示例我们往往弄不清楚各个模块之间的职责和联系。因为不能有效实践,从而被认为会影响开发效率而不被采用。

     这里,我将自己学习总结的知识整理成一篇完整的示例,有提供源代码,源代码包含比较完整的示例,不仅包含数据绑定和命令的使用,还包含UI事件和UI的切换。相信能解释大多数遇到的问题。

    当然,如果你有更好的实践和建议,欢迎讨论……………

 

 1.MVVM设计模式简介

 

     MVVM的设计模式最早于2005年由微软的WPF和Silverlight架构师John Gossman在他的博客中提到。以下是这篇文章的链接:

     http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx

     MVVM设计模式基于MVC这种将UI和逻辑分离的结构思想。传统的.NET平台下软件开发如ASP.NET和WPF/Silverlight大多数是基于CodeBehind这样的方式,我们往往将所有的代码全部写在后台代码文件中,例如UI操作,业务逻辑操作,IO,数据服务的调用等等。这虽然表面上有利于“开发效率”,实际上项目结构不清晰,各个模块之间紧密耦合,不利于扩展,不利于测试。

     MV-X的思想,为.NET平台下的架构提供一种很好的实践。使我们可以构建更利于扩展,结构清晰,职责分明,易测试的软件项目。

     但是目前MVVM模式还没有一个标准的实践,微软也还没有给出相对标准的方案。目前社区讨论的主要是MVVM的思想。在实际开发过程中形成了几种不同的风格。其中以Josh Smith的文章影响比较大:

     http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

     本篇提到的也主要是参考John Smith的思想。

2.采用MVVM设计模式的好处

    

     在Silverlight或者WPF中采用MVVM的架构可以获得以下好处:

     1. 项目可测试更高,从而可以执行单元测试

     2. 将UI和业务的设计完全分开,View和UnitTest只是ViewModel的两个不同形式的消费者

     3. 有助于我们区别并哪些是UI操作,哪些是业务操作,而不是将他们全混在CodeBehind中

     3.项目结构介绍

     以下是示例项目的结构截图:

vs

以下是各模块之间的联系:

org

 

4.WpfMVVMSample.Foundation

     提供一些基础类定义。

5.Model的职责

    

     Model主要提供基础实体的属性以及每个属性的验证逻辑。

     Model不包含数据的调用,但是可以包含简单的非数据调用的操作,如产生序列号或者合并字段。

     对于WCF产生的客户端代理类,Models中应有与之相对应的类结构定义。

     Model不依赖于任何项目。

6.IService和Services以及ServiceTest

     IService是所有网络数据服务或者IO操作的服务接口。

     IService中的数据访问方式以异步为主,见参考示例。

     Service是真实的数据服务访问类,是IService的实现。ServiceTest是用于测试ViewModel的IService的实现

7.ViewModel的职责

    

     ViewModel是MVVM架构中最重要的部分,ViewModel中包含属性,命令,方法,事件,属性验证等逻辑。为了与View以及Model更好的交互来满足MVVM架构,ViewModel的设计需要注意一些事项或者约束:

    ViewModel的属性:ViewModel的属性是View数据的来源。这些属性可由三部分组成:

     一部分是Model的复制属性。

    另一部分用于控制UI状态。例如一个弹出窗口的控件可能有一个IsClose的属性,当操作完成时可以通过这个属性更改通知View做相应的UI变换或者后面提到的事件通知。

    第三部分是一些方法的参数,可以将这些方法的参数设置成相应的属性绑定到View中的某个控件,然后在执行方法的时候获取这些属性,所以一般方法不含参数。

     ViewModel的命令:ViewModel中的命令用于接受View的用户输入,并做相应的处理。我们也可以通过方法实现相同的功能。

     ViewModel的事件: ViewModel中的事件主要用来通知View做相应的UI变换。它一般在一个处理完成之后触发,随后需要View做出相应的非业务的操作。所以一般ViewModel中的事件的订阅者只是View,除非其他自定义的非View类之间的交互。

     ViewModel的方法:有些事件是没有直接提供命令调用的,如自定义的事件。这时候我们可以通过CallMethodAction来调用ViewModel中的方法来完成相应的操作。

8.View及Codebehind

     View中使用Command:View中的Button等控件可以直接绑定Command属性调用ViewModel中的Command

     View中使用CallMethodAction :一些不支持Command的控件,可以用一个CallMethodAction触发器来执行ViewModel中的方法。注意的是方法当中往往包含一些参数,这些参数一般可以通过给ViewModel设置相应的属性来绑定到相关的输入控件,如TextBox。

     View中使用DataTrigger:除了模型属性,还有一部分是状态属性,这往往是ViewModel通过属性更改的方式通知View做出相关的UI操作,例如触发一段动画,或者切换控件状态等等。这个时候可以使用一些触发器,当状态值不同时做出相应的UI变换。

    View的CodeBehind中初始化子View的ViewModel上下文:View一般由父View调用,所以View的ViewModel一般由父View来初始化。比如当点击人脉按钮,需要显示人脉的View的时候,就由主框架初始化人脉的ViewModel,并显示人脉的View。

     View的CodeBehind中订阅子View的UI事件:除了通过状态属性的变更触发View中的触发器,看一种选择是在View的CodeBehind中订阅ViewModel的UI事件。

9.View及ViewModel交互模式总结

由以上解析我们可以总结出View和ViewModel的交互模式:

1. 父View在CodeBehind中初始化子ViewModel

2. 父View在CodeBehind中订阅子ViewModel的UI事件

3. 父View将子ViewModel赋值给子View的DataContext,并显示子View

4. 父View调用子ViewModel获取数据的方法,子ViewModel调用数据服务获取数据

5. ViewModel的数据通过Binding传递给View

6. View接受用户输入,并通过Command或者CallMethodAction交给ViewModel做业务处理

7. ViewModel处理完成之后触发UI事件或者更改状态属性通知父View

8. 父View做出View变换至新的界面

10. 依赖注入

ViewModel的职责是提供数据给View,并调用底层的数据服务。

为了解除ViewModel和BP的耦合,增加一层IService的接口定义,这也使得我们可以构造不同的IService实现来测试ViewModel。

但是View 在使用ViewModel的时候,ViewModel必须要使用IService对象,所以这里采用依赖注入。通过依赖注入来完全解除View以及ViewModel对于Service的依赖。

示例项目源代码下载:

http://files.cnblogs.com/hielvis/WpfMVVMSample.rar


打一广告

正在准备一次北京的技术沙龙活动,目前正在筹备阶段,有兴趣的朋友可以报名,规格在20到50人之间。讨论内容范围待定。以交友为主,技术会友!

QQ群:51825601(北京.NET之友技术沙龙)

备注:此群主要用于组织沙龙活动,仅限北京

欢迎各位朋友捧场!O(∩_∩)O哈哈~

转载于:https://www.cnblogs.com/hielvis/archive/2011/03/22/1991959.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380653.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

32位通用寄存器ESP、EIP、EAX、EBX、ECX、EDX,在OD里操作这些寄存器

EIP:指向CPU下一步即将执行的指令 I EIP为00401000,表示,CPU下一步到00401000这个地址去执行,下一步执行push 0x0指令 ESP:始终指向堆栈的最顶端 现在的ESP是0012FFC4,现在堆栈的顶部在这个地址 EAX、EBX、…

aud to php,HKD to PHP

Exchange1 HKD6.27 PHPExchange 1 港元6.27 菲律宾比索Exchange5 HKD31.36 PHPExchange 5 港元31.36 菲律宾比索Exchange10 HKD62.71 PHPExchange 10 港元62.71 菲律宾比索Exchange50 HKD313.55 PHPExchange 50 港元313.55 菲律宾比索Exchange100 HKD627.11 PHPExchange 100 港…

kotlin 二进制_Kotlin程序检查数字是否为二进制

kotlin 二进制Given a number, we have to check whether given number is a binary or not. 给定一个数字,我们必须检查给定的数字是否为二进制。 Example: 例: Input:start 15end 700Output:[153, 370, 371, 407]在Kotlin中检查数字是否为二进制的…

ComboBox联动

//从webservice中取数据ajax Ext.Ajax.request({ url: WebService.asmx/GetComboxFirst, method: POST, //jsonData: { UserName: "" }, headers: { Content-Type: application/json;utf-8 …

汇编add和mov指令

汇编指令add: 格式:add 参数1, 参数2 功能:参数1和参数2相加,将结果赋值给参数1,即 :参数1参数1参数2 汇编指令 mov: 格式:MOV destination,source 功能:将源…

把.NET程序部署到没有安装.NET Framwork的机器上

摘要本文讨论了如何使用Windows Installer技术发布.NET程序,以及如何使用native代码判断目标机器上是否安装有.NET Framework; 如果没有,将自动安装.NET Framework然后安装作者自己的.NET程序。 ------------------------------------------------------…

双层玻璃窗的功效模型matlab,数学建模:双层玻璃窗的功效,80人%的人搞不懂数学的应用价值...

原标题: 数学建模:双层玻璃窗的功效,80人%的人搞不懂数学的应用价值A.Einstein有一句名言:想象力比知识更重要,因为知识是有限的,而想象力包括世界的一切,推动着进步,并且是知识的源…

Java LinkedList addLast()方法与示例

LinkedList addLast()方法 (LinkedList addLast() method) This method is available in package java.util.LinkedList. 软件包java.util.LinkedList中提供了此方法。 This method is used to insert an object at the last or ending stage of the linked list. 此方法用于在…

8086CPU物理地址

8086CPU有20位地址总线,可以传送20位地址,达到1MB寻址能力,但8086CPU内部是16位,表现出来的寻址能力只有64kb。 8086CPU采用一种在内部用用两个16位地址合成的方法来形成一个20位的物理地址。 CPU中的相关部件提供两个16位地址&a…

json php input,在php中读取json输入

php://输入在localhost中正常工作.但在服务器中它返回空.输入(请求)到我的站点是一个json(REST – 应用程序/ json类型),所以$_POST不起作用(请阅读This question).$_POST works with key-value pair type inputs like form-data or x-www-urlencodedkey1value1&…

8086的CS段寄存器(IP)

8086共有四个段寄存器,分别为CS,DS,SS,ES CS为代码段寄存器,还有个与CS息息相关的寄存器叫IP,为指令指针寄存器。 在8086PC机中,设CS中的内容为M,IP的内容为N,8086CPU将从…

array_reverse_PHP array_reverse()函数与示例

array_reversePHP array_reverse()函数 (PHP array_reverse() function) array_reverse() function is used to returns an array in reverse order, it accepts an array and returns a new array with values in reverse order. array_reverse()函数用于以相反的顺序返回数组…

hibernate中PO对象的三种状态分析以及session中的一些方法的区别

hibernate的状态 hibernate的各种保存方式的区(save,persist,update,saveOrUpdte,merge,flush,lock)及 对象的三种状态 hibernate的保存 hibernate对于对象的保存提供了太多的方法,他们之间有很多不同,这里细说一下,以便区别。 一、预备知识 …

思绪飞扬(一)

喜欢一个呆在房间了,听着音乐,冲一杯香甜的牛奶。任自已的思绪在空气中放飞!似乎这一刻天地之间只有自已。 想想自已已经历了人生的近三分之一的时光。回首之间,二十几年的时间,我们经历了很多事,有…

nginx php fpm 日志,nginx下php-fpm不记录php报错日志怎么办?

解决nginx下php-fpm不记录php报错日志的办法:1、修改【php-fpm.conf】中配置,没有则增加;2、修改【php.ini】中配置,没有则增加;3、重启【php-fpm】即可。解决nginx下php-fpm不记录php报错日志的办法:1.修改php-fpm.co…

jmp、JE、JZ、JNE、JNT指令

JMP JMP 指令无条件跳转到目标地址,该地址用代码标号来标识,并被汇编器转换为偏移量 格式: JMP destination当 CPU 执行一个无条件转移时,目标地址的偏移量被送入指令指针寄存器,从而导致迈从新地址开始继续执行。 …

ruby hash方法_Ruby中带有示例的Hash.length方法

ruby hash方法哈希长度方法 (Hash.length Method) In this article, we will study about Hash.length Method. The working of this method can be predicted with the help of its name but it is not as simple as it seems. Well, we will understand this method with the…

【转贴备忘】[教程]iPhone 實機開發 Part 1 - HelloWorld

http://bbs.weiphone.com/read-htm-tid-222380-page-1.html最近小弟開始在研究 iPhone 的開發,無奈找到的資料都是舊的,也不知道怎麼放到 iPhone 上,應該很多人都跟我有同樣的困擾吧!經過幾天的研究總算寫出第一個 HelloWorld,而且可以不用付99元美金就可以放到實機上執行! 今天…

final 在java,final 在java中的注意点

注意事项慢慢积累final 类不可被继承,也不能有子类。final class Book{}//class ComBook extends Book{} 这将编译失败,因为Book类不可被继承。final方法不可被改写class Book{final void show(){System.out.println("Book的show()方法”)&…

ECC加密算法入门介绍

前言 同RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一样,ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)也属于公开密钥算法。目前,国内详细介绍E…