MVVM 开发的几种模式讨论(WPF)
在WPF系(包括SL,WP或者Win8)应用开发中,MVVM是个老生常谈的问题。初学者可能不会有感觉,但当你写一个核心逻辑能在各种平台上无缝移植,而只需改改UI的时候,那种快感是无法用语言来形容的。
笔者当初接触时,对MVVM并不以为然,编了很多代码以后,反过来看MVVM for WPF的经典文章以后,才若有顿悟。标准的MVVM把程序分成了Model, ViewModel和 View三个部分,但方法是死的,人是活的。我一般的做法是逻辑写一个,View写一个,没有那么严格。为了方便讨论,我们把ViewModel和Model合称Model, View还是View, 分别代表逻辑和界面。分离是肯定的,可是在程序中终究是要把View和Model在某个地方结合起来。 本文就讨论下几种结合的方式。
1. 标准MVVM(由View实例化Model)
标准的MVVM,做法当然是先设计Model, 然后再设计View, 在View的代码里有且仅有这么几句话:
public partial class PluginMangerUI : UserControl
{ public PluginMangerUI()
{
this.InitializeComponent();
PluginManager manager = new PluginManager();
this.DataContext = manager;
}
}
基本的逻辑结构可以用下图来表示。不同的库是由自底向上的方式设计的。

这种由View调用Model, 并具体由View负责Model实例化的方式是最为普遍的,非常适合于需要跨平台的应用。当然,Model并不知道View的存在,因此View要承担所有的界面逻辑,好在WPF已经给出了足够多的解决方案,触发器,模板。基本绝大多数需求都能满足。
2. 插件结构(Model实例化View)
这种做法,是笔者经常用的。在Model里,通过以下代码来实现界面生成
internal class ViewExample : UserControl { }
public class ModelExample : IView
{
private readonly ViewExample view;
public ModelExample()
{
this.view = new ViewExample();
}
public object UserControl
{
get
{
return this.view;
}
}
肯定会有同学问道,怎么会有这么奇怪的写法?这种做法的最常见场合应该是插件系统。一个个的Model其实是一个个的插件,它们应该具备自治性。因此,应该由自身负责界面的产生。
它的好处是可以通过Model更加精细的调节View的行为,你可以在任何时候获得View内部ListBox的SelectIndex, 而不用麻烦的用Binding。 打个比方说,游戏开发中,你需要随时控制物体的运动速度和方向,这样Model就必须控制View. 绑定很难解决这类问题。
我不知道有多少同学在WPF中使用插件的设计思想。若按插件的思路,库应该按功能划分。在这种设计思路下,不同的库便不是自下而上的分层了,而是通过领域和功能分层,如下图:

每一个功能库都有完整的自治性,当你将该功能库拷贝到主框架之下时,它就会自动加载,由Model负责View的生成。一切合情合理。
3. 组装车间(第三方组装View和Model)
这种思路来自于工厂方法,类似于装配车间,View和Model都不负责互相的实例化。而有一个“管理器”负责组装它们。这样的好处在于可配置。你可以通过配置文件动态的改变View.
我记得一种比较著名的WPF向导(Wizard)就是这样的设计思路:
private static List<CompleteStep<DataProcessTask>> CreateSteps(DataProcessTask o)
{
var welcomeModel = new WelcomeModel(o);
var step1ViewModel = new UserCoreModel(o);
var step2ViewModel = new UserDataModel(o);
var step3ViewModel = new ConnectModel(o);
var step6ViewModel = new FinishModel(o); return new List<CompleteStep<DataProcessTask>>
{
/// Each step contains a ViewModel and a View type (the type representing the actual Xaml to be shown).
new CompleteStep<DataProcessTask>
{ViewModel = welcomeModel, ViewType = typeof (Welcome), Visited = true},
new CompleteStep<DataProcessTask> {ViewModel = step1ViewModel, ViewType = typeof (UserCore)},
new CompleteStep<DataProcessTask>
{ViewModel = step2ViewModel, ViewType = typeof (UserDataView)},
new CompleteStep<DataProcessTask> {ViewModel = step3ViewModel, ViewType = typeof (Connect)},
new CompleteStep<DataProcessTask> {ViewModel = step6ViewModel, ViewType = typeof (Finish)}
};
}
如上图所示,DataProcessTask类是控制整个流程的核心,第一步先实例化所需的ViewModel, 第二部,通过构建一个List列表,将View的Type的方法传到列表中。最终管理器通过反射来实例化View,并将DataContext绑定到对应的ViewModel完成整个组装过程。
可以看出,这种做法彻底的隔绝了View和Model, 同时通过配置选项,可以随时修改View。可谓是一种不错的设计。 但是,必需看到,对于View来说,Model没有任何管理的权限。下图展示了它的基本逻辑:

如果最终你依旧需要两边互相控制,可以考虑采用dynamic关键字。
4. 总结
其实没有哪种方式是最好的,完全是看你对整个系统的设计需求。但不论如何,界面和逻辑的分离,这是毋庸置疑的。下面的表格总结了几种做法的特点和适用场合:
| 名称 | 组装逻辑 | 适用场合 | 缺点 | 备注 |
| 标准MVVM | View实例化Model | 常用的跨平台场合 | Model无法控制任何View | 适用于自底向上的分层设计 |
| Model实例化View | Model实例化View | 插件结构或用于游戏开发 | 存在一定的耦合 | 适用于按功能划分的插件型类库设计,或要求Model大量控制View的场合 |
| 组装车间 | 第三方管理器实例化和组装Model和View | 可动态替换所有View | 两者彻底隔绝,没有控制灵活性 | 大型系统的严格设计 |
当然,如果用MVVMLight等第三方类库的话,就应该按照它的方案去开发。但我们的原则是,解决问题,但不要引入更复杂的问题。为了解耦,搞了大量的复杂逻辑,反而舍本逐末。
有任何问题,欢迎随时讨论。
MVVM 开发的几种模式讨论(WPF)的更多相关文章
- 笔记03 MVVM 开发的几种模式(WPF)
转自http://www.cnblogs.com/buptzym/p/3220910.html 在WPF系(包括SL,WP或者Win8)应用开发中,MVVM是个老生常谈的问题.初学者可能不会有感觉,但 ...
- APP开发的三种模式
Hybrid APP混合开发的一些经验和总结 APP开发的三种模式:Native App .web App.hybrid App 1.原生app 使用原生app (android或iOS)开发APP. ...
- 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器
从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器 之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Calibu ...
- js架构设计模式——理解javascript中的MVVM开发模式
理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...
- 企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(3)
第一章 表现模式关注分离(soc)是企业及软件开发中非常有用的核心原则,也是许多表现模式背后的驱动力量.在WPF和Silverlight开发中,MVVM成为了实现关注分离最为有效的设计模式.然而,这种 ...
- android中MVC,MVP和MVVM三种模式详解析
我们都知道,Android本身就采用了MVC模式,model层数据源层我们就不说了,至于view层即通过xml来体现,而 controller层的角色一般是由activity来担当的.虽然我们项目用到 ...
- 简述 MVC, MVP, MVVM三种模式
Make everything as simple as possible, but not simpler - Albert Einstein* 把每件事,做简单到极致,但又不过于简单 - 阿尔伯特 ...
- 企业级架构 MVVM 模式指南 (WPF 和 Silverlight 实现) 译(2)
本书包含的章节内容 第一章:表现模式,以一个例子呈献给读者表现模式的发展历程,我们会用包括MVC和MVP在内的各种方式实现一个收费项目的例子.沿此方向,我们会发现每一种模式的问题所在,这也是触发设计模 ...
- App开发三种模式
APP开发三种模式 现在App开发的模式包含以下三种: Native App 原生开发AppWeb App 网页AppHybrid App 混合原生和Web技术开发的App 详细介绍: http:// ...
随机推荐
- 【WPF】WPF中的List<T>和ObservableCollection<T>
在WPF中 控件绑定数据源时,数据源建议采用 ObservableCollection<T>集合 ObservableCollection<T> 类:表示一个动态数据集合,在添 ...
- CSS中"!important"的使用
本篇文章使用最新的IE10以及firefox与chrome测试(截止2013年5月27日22:23:22) CSS的原理: 我们知道,CSS写在不同的地方有不同的优先级, .css文件中的定义 < ...
- 详解Java GC的工作原理+Minor GC、FullGC
详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...
- 我的第一段jQuery代码
说起 jQuery,很多人可能觉得,不算什么,就是个js类库.而,对于我,下面这几行代码,是一个新的开始. 多年来,我一直在使用MooTools ,他面向对象,写起来结构清晰分明,都是在原生js的基础 ...
- 玩转动态编译 - 高级篇:一,IL访问静态属性和字段
IL介绍 通用中间语言(Common Intermediate Language,简称CIL,发音为"sill"或"kill")是一种属于通用语言架构和.NET ...
- ASP.NET MVC 5 - 创建连接字符串(Connection String)并使用SQL Server LocalDB
您创建的MovieDBContext类负责处理连接到数据库,并将Movie对象映射到数据库记录的任务中.你可能会问一个问题,如何指定它将连接到数据库? 实际上,确实没有指定要使用的数据库,Entity ...
- 【原】通过JS打开IE新tab(非Window)的解决方案
近日项目里遇到限定在IE的tab窗口里打开新窗口的需求,结合网上的资源和亲自实践,总结以下比较可行的解决方案. 1.首先必须保证IE的设置正确.打开IE的Internet options ->G ...
- 蓄水池(Reservoir_sampling)抽样算法简记
摘要 1.适用场合 2.算法简介 3.代码例子 4.Spark RangePartitioner 中的应用(待补充) 内容 1.适用场合:从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数 ...
- 我所理解的Cocos2d-x
我所理解的Cocos2d-x(完全基于Cocos2d-x3.0,深度剖析计算机图形学,OpenGL ES及游戏引擎架构,全面提升游戏开发相关知识) 秦春林 著 ISBN 978-7-121-246 ...
- C#设计模式-原型模式
在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中分配 ...