WPF中的MVVM模式

"设计模式"这样的话题彷佛快被园子里的兄弟们写透了, 从简单的工厂到 MVC, MVP. 而关于MVVM彷佛谈论得相对少些, 今天简单地说说. 值得声明的是: 这里仅仅谈论得是本身对别人发明的东西的一些理解, 可能有所偏误, 望理解. 另外, 搜索了一下,园子里 "clingingboy" 和 "高阳"大哥也谈到了这个模式, 你们不妨参考一下.
在阅读如下内容之前,建议你对这些内容有所了解: WPF, MVC, MVP, MVVM. 关于MVVM语法层面的内容请参考这里: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

1, 前提
能够说MVVM是专为WPF打造的模式, 也能够说MVVM仅仅是MVC的一个变种, 但不管如何, 就实践而言, 若是你或你的团队没有使用"Binding"的习惯, 那么研究MVVM就没有多大意义.
另外,我的以为, 使用Command以及打造一种合理的简化的方式去使用Command也与使用Binding同样重要.

2, 诞生
为了解决现实世界中的问题,咱们须要将现实世界中的事物加以抽象, 而后获得了Domain Object, 不管贫血的仍是富血的, 咱们均可以简单地把他们归结为"由现实世界抽象出来的模型", 也就是咱们的model, 也就M-V-VM中的"M".
但其没法与咱们的用户进行交互, 因此, 咱们须要为其建立一个界面(视图, View), 该视图能够与用户输入设备进行交互, 这很棒, 但问题是如何将View与咱们的model关联起来? Binding即可以发挥做用了, 好比视图上的某一个文本框中的文本和Model中的"用户名"关联起来, 用户即可以经过操做该文本框来访问和修改Model的"用户名"了.
这是极其简单的状况, 但实际编程时咱们发现, Model中的属性(与方法)每每不那么容易与View中的界面控件关联起来, 好比, "类型不匹配": 界面控件所须要的类型与模型中属性提升的类型不匹配. "须要额外操做": 模型中的数据须要通过一些额外的处理才能传给视图,反之亦然. 此时, 咱们意识到View彷佛须要一个"Helper"类来处理一些额外工做.
这个helper所包含的代码能够放在除了Model外的不少地方(咱们如今不考虑贫血富血之类的争论), 好比View中, 记得本身刚学习窗体程序开发时就是这么干的, 将绝大多数处理逻辑放在那个所谓的CodeBehind中. 后来,正如你们在各类设计模式书籍中所看到的同样,为了将View和Model剥离开来,实现view可替换(好比你能够讲本身精心设计的软件同时运行于窗体程序,Web甚至Mobile上), 便有了MVC. 有了MVC之后彷佛就开始滋生M-V-XXX之类的争论与变种模型, 好比MVP以及这里的MVVM,甚至MVP也有着Supervising Controller与Presentation Model两种方式. 但主要围绕两个问题,一是model与view之间的关系, 彻底隔离的?单向的仍是双向的? 二是这个"XXX"须要完成哪些功能,简单流程调度?复杂规则处理? OK,这些争论都没有关系, 是否采用某种模式取决于你的开发所处的环境(好比语言特性,框架特性)以及你的业务特性以及所面临的主要变化点等等.
但与MVC,MVP所不一样的是,MVVM的引入不只仅是技术上的缘由(解除耦合应对变化等老生常谈),另一个很大缘由是:软件团队开发方式的改变.若是你作过一段时间的WPF项目开发的话,你可能会有比较明显的感受:在View层打造上,如何分配程序员和美工的工做.在继续阅读以前,你们能够看看我之前的一篇文章"在UI Designer与Developer之间". 之前咱们团队采用的即是"集成模式", 我便兼职了其中的"Integrator"角色.这还不错.但说实在的,这仅仅是一个在特殊状况下不得已而为之的暂时方案,因此咱们付出了很大的努力开始转向"收割模式"了,要转向这个模式,至少须要两个基本条件:
(1)你拥有可以熟练运用Blend等工具能为程序员输出XAML的美工, 他专一于纯粹的UI/UE, 另外他还必须具备必定的"程序员"思惟.以便输出的东西能很好地做为程序的一部分而运转起来,而不是仅仅"看上去"是那样的.
(2)你须要可以脱离View层但仍能编写出高质量代码的程序员.
幸运的是, 咱们在努力创造条件1,并取得了很好的效果.(你能够招一个具备Flash脚本编写经验的而且有极大的学习热情的美工人员, 并对他进行Blend的相关培训). 而MVVM模式为咱们实现第二个条件提供了极大的便利. 为何MVC/MVP模式不行而MVVM能够呢? 很简单, 在MVC和MVP模式中, View层都具备不少代码逻辑, 开发View层的是程序员, 虽然UI/UE团队会作不少工做, 但这个层的"实现者"仍然是程序员. 在之前的开发中,其工做得很好, 而在WPF开发中程序员对View层的展示显得力不从心了,美工(指符合上面条件1的美工)虽然很擅长, 但他会说"惋惜我不会程序".因而, 咱们须要一种方式将View层的代码逻辑抽取出来,并View层很纯粹以便彻底让美工去打造它.相应地, 须要将View层的相应逻辑抽取到一个代码层上,以便让程序员专一在这里.
回想一下, 咱们只因此要在View(Xaml)背后写一些代码(C#), 无非是想传递一些数据以及传递数据时的数据的处理或在用户与界面控件进行交互时执行一些操做, 最简单的例子是在MVC中当界面发生交互时View去调用Controler中的某个方法, 以便将该操做的相应"指示"传递到"后台"去. 在之前的技术中, 这样的"衔接性"的代码是必须的. 而在WPF中, 则能够经过另外的技术来进行层与层之间的"衔接", 这就是"Binding" 和"Command", 以及稍后咱们会提到的"AttachBehavior". 经过Binding, 咱们能够实现数据的传递; 经过Command, 咱们能够实现操做的调用.(AttachBehavior的做用稍后再谈). Binding和Command是能够写在XAML中的, 这样看来XAML后面对于的CS文件能够被彻底抛弃或不予理会了. 这样的XAML文件正是美工所须要的. 而这些对于Binding以及Command的定义描述以及其余相关信息的代码应该放在那里呢, 固然不是View, 更不是Model, 是"ViewModel". ViewModel是为这个View所量身定制的, 它包含了Binding是所需的相关信息,好比Converter以及为View的Binding提供DataContext, 它包含了Command的定义以便View层能够直接使用, 另外,它仍是一个变种的Controler, 它得负责业务流程的调度.
因而, 便有了这副图, 而后, 正如"时势造英雄"所言, MVVM就诞生了.

3, ViewModel 与 单元测试
若是你是一名正在使用MVVM模式打造软件的程序员, 那么我劝你尽快忘掉View. 你所面对的是这样一个模式"UnitTest-ViewModel-Model"(这并不是一个模式, 仅仅是我为阐述观点而暂时如此表述的).
记得曾经有一个Model-View-AbstractView模式, 而MVVM中的VM实际也是一个AbstractView: the abstraction of view. 它是一个抽象的View, 具备一个View的灵魂,而不具有相应的可视化控件而已. 因此对于程序员而已, 打造这样一个抽象的VM就能够认为是完成View层的打造了.而当美工完成无数控件组成的实际的View后, 咱们就能够用Binding和Command这样的黏合剂将这个抽象的View和实际的View黏合在一块儿了.
那么在黏合以前, 咱们怎么知道本身的VM是否正常工做呢? 单元测试!
在说明对于ViewModel进行单元测试的重要性以前, 送给你们一句话: "View and Unit Test are just two different types of ViewModel consumers" (Josh Smith). 若是咱们将ViewModel看做生产者, 那么View和Unit Test都是具备同等地位的消费者而已. 而且UnitTest相比于View而言具有更大的消费能力. 或者你能够简单的认为View也仅仅是一种不太推荐的测试方式而已. 因此要实施好这个模式, 那么对ViewModel的单元测试就是必须的了,而且这个测试要不依赖于任何UI控件. (那么不是不对应ViewModel的开发是否是就应该经过测试来驱动了?TDD?)

4, AttachBehavior
通常状况下利用Command, Binding, AttachProperty等WPF特性, View和ViewModel之间能配合工做得很好. 假设咱们有一个Button, 当该Button被点击的时候咱们要完成一些操做, 很简单, 将该操做封装成一个Command并绑定到该Button上就能够了, 但若是咱们要在Button被Load的时候执行另一些操做呢? 因为Button没有直接被Load事件所触发的Command
, 因此不能使用Command了. 不能直接将Load事件处理器写在Button所在的Xaml所对应的CS文件里, 这和咱们刚才对MVVM的设计是相矛盾的. 一个不太好的方案是继承一下Button, 并撰写一个由Load所触发的Command, 这可行, 但明显很差. 正如一个控件没有某个属性而且在不继承的状况下而采用AttachProperty同样, 咱们能够采用AttachBehavior. AttachBehavior不是WPF特性, 它仅仅是一个最佳实践, 一个Pattern. 关于AttachBehavior语法如何书写, 请参考 : http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx

html

http://www.cnblogs.com/zhouyinhui/archive/2009/07/23/1529524.html程序员

相关文章
相关标签/搜索