谢伟
摘 要:MVVM即Model-View –ViewModel,是微软WPF和Silverlight应用特有的一种界面设计模式。使用MVVM设计模式可以帮助我们分离业务逻辑,显示逻辑和用户界面,使得我们的程序代码结构清晰,容易被阅读、测试、维护、替换、扩展和改进。
关键词: MVVM;设计模式;分层;用户界面
一、什么是MVVM模式
MVVM是Model-View-ViewModel的简写。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……。这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性揉合进去,以应对客户日益复杂的需求变化。
二、为什么要有MVVM模式
开发UI,对一个专业软件并不容易。它需要未知数据、交互式设计,可视化设计、联通性,多线程、国际化、验证、单元测试以及其他的一些东西才能完成。考虑到UI要展示开发的系统并且必须满足用户对系统风格不可预知的变更,因此它是很多应用程序最脆弱的地方。
有很多的设计模式可以帮助解決UI不断变更这头难缠的野兽,但是恰当的分离和描述多个关注点可能很困难。模式越复杂,之后用到的捷径越可能破坏之前正确的努力。
自从人们开始构建UI时,就有很多流行的设计模式让UI构建更容易。比如,MVP模式在各种UI编程平台中都非常流行。MVP是MVC模式的一种变体,MVC模式已经流行了几十年了。MVVM比MVP更加简单,更不用说MVC了。MVVM是在MVP之后出现的一种“更好的”UI模式解决方案。
如图1,展现了MVVM是如何做到井然有序的。
图1 MVVM模式图解
(1)View中很多控件的数据类型和Model中的属性不相同,例如开发中,性别这种,Model中很可能就放置一个bool类型的变量。但是在前台的展现View中,用户看到的应该是“男”和“女”。这就需要一种转化。
(2)在WPF开发中事件和命令同样都可以让一个UI正常的工作。我们知道Winform是事件驱动的。所以理所当然使用事件更容易理解和实现。但是带来的问题是后期的庞大与多种多样的事件。
这两种问题很大的催生出Model和View中间的一个辅助角色ViewModel。它需要帮助View转化相应的数据给Model或者从Model处转化成View可以显示的内容。同时它也需要将View的多种命令绑定给Model中的处理方法上。这些命令可以复用,当其他View需要的时候,同样可以调用命令中绑定的方法。ViewModel可以看成一个变种的Controller。
三、实现原理
解决了上一节提出的两个问题,实际上就解决了ViewModel的全部工作原理。
首先,从Binding问题入手。在View中的控件存在一个属性,叫做“DataContext”。这个是控件数据使用的源头。DataContext属性会给控件指定一个后台模型,使得该控件使用的数据都是来自于这个模型类。所以,ViewModel应该充当这个后台模型的作用,给View的控件提供显示数据。同时,ViewModel的数据应该是来自于背后的Model所提供的。所以,简要的说,根据View中显示的数据是何种Model,来定义ViewModel。举个例子,如果View构造了一个TextBlock控件,想要显示的仅仅是Model中的一个string。那么在ViewModel中,应该引用这里的Model,这样作为View部分,就可以调用这个Model的某个string属性了。
其次,解决Command问题。WPF中已经构建了实现了ICommand的类RoutedCommand和RoutedUICommand。针对于不同的View事件,单独使用哪一种都不是全权之策。因此,需要定义一个实现了ICommand接口的类。目前网上有现成的DelegateCommand和RelayCommand两种解决方法。他们的共同点都是实现了ICommand接口,同时对于不同的事件,都可以绑定Model不同的处理方法。其区别是:i)DelegateCommand使用了一个RaiseCanExecuteChanged方法,需要开发者手动来触发控件可执行判断。而RelayCommand中对于此处的触发判断是代理给CommandManager自己判断了。更加方便;ii)DelegateCommand因为是开发者手动控制的,所以资源占用低,而RelayCommand在各种命令触发的时候都需要判断一下。所以资源占用也相对较高。这一点尤为能体现在复杂的系统中。所以使用哪一个都是看开发人员自己选择。当然也可以自己手动写一些更加适合自己的XXXCommand。其实现原理就是实现了ICommand接口。另外,使用委托的方法,将无返回值的Execute使用Action委托,有返回值的CanExecute使用Func委托。
参考文献:
[1]陈明、李猛坤、张强.一种基于扩展MVVM模式的SaaS面向服务计算模型[J].微电子学与计算机,2010年08期
[2]李猛坤、陈明.一种基于扩展MVVM模式的面向服务软构件模型[J].科学技术与工程,2011年10期