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、…

汇编add和mov指令

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

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

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

8086CPU物理地址

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

8086的CS段寄存器(IP)

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

思绪飞扬(一)

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

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…

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

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

DS和[address]

8086CPU中,用16位寄存器来存储一个字。高8位存放高位字节,低8位存放低位字节。在内存中存储时,由于内存单元是字节单元,则一个字要用两个地址连续的内存单元来存放,这个字的低位存放低地址单元中,高位字节存…

计算机指令格式_计算机科学组织| 指令格式

计算机指令格式指令格式 (Instruction format ) Instruction format describes the internal structures (layout design) of the bits of an instruction, in terms of its constituent parts. 指令格式按照指令的组成部分描述指令位的内部结构(布局设计)。 An Instruction fo…

ejs获取js变量值_EJS变量(注入值)

ejs获取js变量值Hi! Welcome to NODE AND EJS TEMPLATE ENGINE SERIES. Today, we will talk about EJS variables or how we can inject values? 嗨! 欢迎使用NODE和EJS模板引擎系列。 今天,我们将讨论EJS变量或如何注入值? Just like nor…

Visual Basic 9.0 前沿播报·静态篇(六)松弛委托和可为空类型语法增强

本期介绍的两个VB9作为数据开发辅助功能的新特性。CLR在.NET 2.0增加了许多关于委托的新特性(但大部分都不为任何语言所支持),其中一个叫做协变的特性允许放松委托与函数绑定时的签名检查(C# 2.0支持)。为了追求更高的…

3年前的小程序:破解需要delphi IDE 环境的vcl 控件

基本原理:有些vcl组件未注册的话,会显示没有注册的信息,但在设计期间不显示这些信息,表示该组件会检查delphi的ide 环境,解决办法就是让自己的exe带上ide的信息;组件检查ide的办法无非就是使用api查找特定的…

执行POP和PUSH指令后,SS和SP的变化

我们知道push指令是将数据送入栈中,pop指令是将数据从栈顶取出来,8086CPU的入栈和出栈操作都是以字为单位的 比如说将10000H-1000FH这段内存当做栈使用 CPU是通过CS、IP中存放的段地址和偏移地址来知道当前要执行的指令,通过DS和[address]来…

win7 php 上传文件,在LNMP原来的基础上,win7环境下如何上传PHP文件到Linux环境下...

首先,下载一个WINSCP客户端连接主机后,上传文件到自己的保存目录接着进入数据库添加我们的数据库mysql -uroot -p //这个是进入mysql的命令,但是要是你没有加 ln -s /usr/local/mysql/bin/mysql /usr/bin 的话就要输入下面那一行/usr/loc…

HDFC的完整形式是什么?

HDFC:住房发展金融公司 (HDFC: Housing Development Finance Corporation) HDFC is an abbreviation of Housing Development Finance Corporation. It is a well-known housing expansion finance corporation of India which largely makes available housing loa…

将10000H-1000FH这段空间当做栈,初始状态栈是空的,设置AX=001AH,BX=001BH,利用栈,交换AX和BX的数据

程序: mov ax,1000H mov ss,ax mov sp,0010H;设置AX和BX的值 mov ax,001AH mov bx,001BH;压栈 push ax push bx;出栈 pop ax pop bx解释: 在8086中,段寄存器不能直接传值,要通过一般寄存器,所以先将值传到ax中&#x…

php having,having方法

having方法1、对分组统计的结果,进行筛选如果将分分组查询的结果看成一张表的话,having方法类似where语句的功能2、源码:/thinkphp/library/think/db/Query.php/*** 指定having查询* access public* param string $having having* return $th…

Linux:jumpserver介绍(1)

官方网站 JumpServer - 开源堡垒机 - 官网https://www.jumpserver.org/ JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。JumpServer 帮助企业以更安全的方式管控和登录所有类型的资产,实现事前授权、事中监察、事后审计&…

对一个简单汇编程序分析

程序: assume cs:codesgcodesg segmentmov ax,0123Hmov bx,0456Hadd ax,bxadd ax,axmov ax,4c00Hint 21Hcodesg endsend伪指令: 伪指令是写给编译器看的,CPU不会执行,在源程序中,包括两种指令,一个是…