转自http://www.cnblogs.com/buptzym/p/3220910.html

在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等第三方类库的话,就应该按照它的方案去开发。但我们的原则是,解决问题,但不要引入更复杂的问题。为了解耦,搞了大量的复杂逻辑,反而舍本逐末。

有任何问题,欢迎随时讨论。

笔记03 MVVM 开发的几种模式(WPF)的更多相关文章

  1. MVVM 开发的几种模式讨论(WPF)

    在WPF系(包括SL,WP或者Win8)应用开发中,MVVM是个老生常谈的问题.初学者可能不会有感觉,但当你写一个核心逻辑能在各种平台上无缝移植,而只需改改UI的时候,那种快感是无法用语言来形容的. ...

  2. APP开发的三种模式

    Hybrid APP混合开发的一些经验和总结 APP开发的三种模式:Native App .web App.hybrid App 1.原生app 使用原生app (android或iOS)开发APP. ...

  3. js架构设计模式——理解javascript中的MVVM开发模式

    理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...

  4. android中MVC,MVP和MVVM三种模式详解析

    我们都知道,Android本身就采用了MVC模式,model层数据源层我们就不说了,至于view层即通过xml来体现,而 controller层的角色一般是由activity来担当的.虽然我们项目用到 ...

  5. 简述 MVC, MVP, MVVM三种模式

    Make everything as simple as possible, but not simpler - Albert Einstein* 把每件事,做简单到极致,但又不过于简单 - 阿尔伯特 ...

  6. jsp学习笔记:mvc开发模式

    jsp学习笔记:mvc开发模式2017-10-12 22:17:33 model(javabe)与view层交互 view(视图层,html.jsp) controller(控制层,处理用户提交的信息 ...

  7. App开发三种模式

    APP开发三种模式 现在App开发的模式包含以下三种: Native App 原生开发AppWeb App 网页AppHybrid App 混合原生和Web技术开发的App 详细介绍: http:// ...

  8. Android(java)学习笔记219:开发一个多界面的应用程序之两种意图

    1.两种意图: (1)显式意图: 在代码里面用intent设置要开启Activity的字节码.class文件: (2)隐式意图: Android(java)学习笔记218:开发一个多界面的应用程序之人 ...

  9. python编程(python开发的三种运行模式)【转】

    转自:http://blog.csdn.net/feixiaoxing/article/details/53980886 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 单循环 ...

随机推荐

  1. Linux定时任务Crontab命令详解 转

      linux 系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的.另 外, 由于使用者自己也可以设置计划任务,所 ...

  2. 设计模式(二 & 三)工厂模式:1-简单工厂模式

    模拟场景: 需要构造一个运算器(Operation),分别负责加减乘除的运算功能. 思想: 这里需要构造四个 Operation,可以使用 Factory 去统一创建这四个对象. 所需要构造的对象是运 ...

  3. windows10下安装ubuntu16.04 双系统

    软件和材料:   UltraISO .ubuntu16.04镜像.U盘 步骤: 1.先在windows10 上下载UltraISO并安装 2.打开UltraISO,插入优盘,制作ubuntu160.4 ...

  4. 【Codevs1034】家园(最大流,裂点)

    题意:由于人类对自然的疯狂破坏,人们意识到在大约2300年之后,地球不能再居住了,于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177年冬由于未知的原因,地球环境发生了连锁崩溃,人 ...

  5. net5:动态修改内存中的站点地图节点

    原文发布时间为:2008-07-29 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  6. 转载 linux 僵尸进程,讲的很透彻

    僵尸进程的产生和避免,以及wait,waitpid的使用 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitp ...

  7. LeetCode OJ--Binary Tree Preorder Traversal

    http://oj.leetcode.com/problems/binary-tree-preorder-traversal/ 二叉树的先跟遍历,写的是递归版本,也可以使用stack来进行,替代了递归 ...

  8. Python Challenge 第四关

    进入了第四关.只有一张图,我还是像往常一样查看源代码.果然,发现了一行注释:urllib may help. DON'T TRY ALL NOTHINGS, since it will never e ...

  9. 关于udo3d双目相机的嵌入式板子系统重装

    遇到的问题: 1.下载压缩文件(.rar):在linux下下载一会就会停止 原因:linux下不支持.rar文件的下载,在windows下载即可 2.在windows下解压文件,结果为镜像文件(.im ...

  10. (BruteForce)暴力破解经典题目总结

    在算法竞赛中,很多问题是来不及用数学公式推导出来的.或者说根本就找不到数学规律,这时我们就需要使用枚举来暴力破解. 不过枚举也是需要脑子的,一味的暴力只能超时.因此我这里选择了几道mooc上经典的题目 ...