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;
        }
    }
复制代码

 

 基本的逻辑结构可以用下图来表示。不同的库是由自底向上的方式设计的。

image

    这种由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中使用插件的设计思想。若按插件的思路,库应该按功能划分。在这种设计思路下,不同的库便不是自下而上的分层了,而是通过领域和功能分层,如下图:

image

  每一个功能库都有完整的自治性,当你将该功能库拷贝到主框架之下时,它就会自动加载,由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没有任何管理的权限。下图展示了它的基本逻辑:

image

  如果最终你依旧需要两边互相控制,可以考虑采用dynamic关键字。

4. 总结

    其实没有哪种方式是最好的,完全是看你对整个系统的设计需求。但不论如何,界面和逻辑的分离,这是毋庸置疑的。下面的表格总结了几种做法的特点和适用场合:

名称 组装逻辑 适用场合 缺点 备注
标准MVVM View实例化Model 常用的跨平台场合 Model无法控制任何View 适用于自底向上的分层设计
Model实例化View Model实例化View 插件结构或用于游戏开发 存在一定的耦合 适用于按功能划分的插件型类库设计,或要求Model大量控制View的场合
组装车间 第三方管理器实例化和组装Model和View 可动态替换所有View 两者彻底隔绝,没有控制灵活性 大型系统的严格设计

    当然,如果用MVVMLight等第三方类库的话,就应该按照它的方案去开发。但我们的原则是,解决问题,但不要引入更复杂的问题。为了解耦,搞了大量的复杂逻辑,反而舍本逐末。

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


作者:热情的沙漠
出处:http://www.cnblogs.com/buptzym/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

标签: .NET

本文转自FerventDesert博客园博客,原文链接:http://www.cnblogs.com/buptzym/p/3220910.html,如需转载请自行联系原作者
目录
相关文章
|
8月前
|
设计模式 开发框架 前端开发
深入理解WPF中MVVM的设计思想
近些年来,随着WPF在生产,制造,工业控制等领域应用越来越广发,很多企业对WPF开发的需求也逐渐增多,使得很多人看到潜在机会,不断从Web,WinForm开发转向了WPF开发,但是WPF开发也有很多新的概念及设计思想,如:数据驱动,数据绑定,依赖属性,命令,控件模板,数据模板,MVVM等,与传统WinForm,ASP.NET WebForm开发,有很大的差异,今天就以一个简单的小例子,简述WPF开发中MVVM设计思想及应用。
62 0
|
10月前
|
前端开发 算法 JavaScript
走进WPF之MVVM完整案例
走进WPF之MVVM完整案例
156 0
|
前端开发 数据可视化 C#
WPF MVVM系统入门-上
本文详细讲解WPF,MVVM开发,实现UI与逻辑的解耦。
|
前端开发 C# 数据库
WPF MVVM系统入门-下
本文详细讲解WPF,MVVM开发,实现UI与逻辑的解耦。
|
SQL 前端开发 C#
WPF MVVM模式
WPF MVVM模式
|
前端开发 C# 架构师
【我们一起写框架】MVVM的WPF框架(三)—数据控件
这世上,没人能一次性写出完美无缺的框架;因为,任何一个框架都需要项目的淬炼,然后才能升华,趋近完美。 所以,框架是个反复修改的东西,最终形成的东西。 如果你学了一点技术,觉得自己可以写出框架了,觉得自己有架构师的能力,然而自己总是怀才不遇——那一定是你的错觉。
1148 0
|
前端开发 C#
【我们一起写框架】MVVM的WPF框架(二)—绑定
MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新。 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。 那么现在就要开始实现数据同步了。
1478 0
|
前端开发 架构师 程序员
【我们一起写框架】MVVM的WPF框架(一)—序篇
前言我想,有一部分程序员应该是在二三线城市的,虽然不知道占比,但想来应该不在少数。 我是这部分人群中的一份子。 我们这群人,面对的客户,大多是国内中小企业,或者政府的小部门。这类客户的特点是,资金有限,人力有限。
1524 0