摘要
WPF企业内训全程实录由于文章比较长,所以一共拆分成了三篇,上篇WPF企业内训全程实录(上)主 要讲了基础,这篇作为该实录的中篇,起着承上启下的作用,主要讲解开发模式、团队协作及应用框架。其实如果大家仔细看目录,可以发现我安排的顺序是首先讲 解最基本的概念和基础内容、然后过渡到开发模式及框架、最后结合其他技术和项目实际运用,这也是学习并应用一门技术最好的流程。上篇实际上主要有两个侧重 点:一则就是理清脉络——历史渊源、概念引入及基本阐述;二则是讲解WPFBasic——主要讲解WPF的每个知识点,涵盖了WPF的方方面面;如果大家 感兴趣,可以下载代码进行仔细研究,如果有不懂的地方也可以参考我写的WPF 基础到企业应用系列,这里受篇幅限制,就不详细论述。今天的中篇主要围绕WPF开发模式、WPF团队协作和MVVM框架三个议题进行阐述,希望能给大家带来一些参考和帮助。
章节纲要
- · 1.摘要
- · 2.本文提纲
- · 3.简要介绍
- · 4.WPF介绍
- · 5.WPF基础
- · 6.WPF工具
- · 7.WPF开发模式
- · 8.WPF团队协作
- · 9.了解并使用MVVM框架
- · 10.自己开发MVVM框架
- · 11.其他技术引入
- · 12.WPF项目及性能优化
- · 13.部署与更新
- · 14.总结
- · 15.详细技术索引
七. WPF开发模式
提到WPF开发模式(这里通常所说的是Presentation模式,其他层的模式不在此列),大家可能会立马想到MVC/MVP/MVVM模式:
- 1,MVC:模型-视图-控制器(Model View Controller)
- 2,MVP:模型-视图-表现类(Model-View-Presenter)
- 3,MVVM:模型-视图-视图模型(Model-View-ViewModel)
的确,时下流行的就这三种常见的Presentation模式(这三种模式又衍生了很多变种),从根本上说这些模式是为了解决如下的几个问题:
- 1,逻辑与UI紧密耦合,更换UI上的显示往往需要更改很多逻辑代码,正所谓“牵一发而动全身”。
- 2,应用程序状态的维护,主要包括状态 (State) , 逻辑 (Logic) ,同步 (Synchronization)耦合太紧。
- 3,不能使不同的UI共享相同的逻辑(复用问题)。
- 4,要测试用户界面效果,你需要做复杂的UI测试。
- 5,团队协作不能充分发挥,因为耦合太紧的关系。
- 6,维护比较困难,这也是由于耦合紧密且没有完整的单元测试。
之前的C/S(WinForm)和B/S(ASP.NET/ASP.NET MVC)我们已经习惯了MVC和MVP模式,现在针对WPF和Silverlight的具体特征——它带来了3D、动画、音频、视频……这导致了UI的变 化将更加细节化和可定制化。同时,在技术层面上,WPF和 Silverlight也带来了诸如Binding、 Dependency Property、Routed Events、Command、Attached Behavior(依赖属性体系间接实现)、DataTemplate、ControlTemplate等新特性。我们怎样才能立足于原有的技术框架并把 WPF/Silverlight的新特性揉合进去,以应对客户日益复杂且多变的需求呢?那么MVVM模式就是一个不错的选择,详见如下框架图:
图1
在MVVM模式中,你需要一个为View量身定制的model,那么这个model实际上就是上图ViewModel。ViewModel包含 所有UI所需要的接口、属性和命令,这样只需要通过Binding使他们进行关联,就可以使二者之间达到松散耦合,所以这样一来,UI就可以由UI专业人 员用Design和Blend来实现(当然很多效果还是需要用传统的制图软件,所以我们都称这种想法叫理想状态),代码人员也可以专心写他的逻辑和业务代 码,所以这样分工和协作变得更轻松、更愉快了。更漂亮的是View完全可以由(Unit/Automatic Test)所取代,所以单元测试也变得相对简单。这对于我们的开发人员和测试人员无疑是一个很好的解脱,同时也提高了系统的可测性、稳定性和维护性。数据 绑定系统同时也提供了标准化的方式传输到视图的错误验证和输入验证(但是个人觉得不是很好用,所以我们在实际的项目当中会写一套自己的验证框架)。
讲到这里,我们这里不得不引入下面这幅图,我觉得它能阐述一些比较重要问题:
图2(注:此图引用自Robert McCarter的MVVM一文)
上面的这幅图表达了几个概念:
- 1,Domain Model 始终是应用程序的核心,必须投入大量精力,按照面向对象的分析和设计 (OOAD) 最佳做法进行设计同时按照OOP进行开发。
- 2,Model、View 和 ViewModel 层之间实施严格的分离,也强调了它们之间是一种松散耦合的关系。
- 3,每一层或者每一个模块都有自己完整的单元测试,这样即提高了代码质量,同时也增强了稳定性和可维护性。
- 4,不要为了MVVM而MVVM,不要强调UI端不产生一句后台代码而把所有代码都扔进ViewModel,因为有的操作如果不参与逻辑流程,放在UI端处理会更好,这也符合UI和逻辑隔离的最终原则。
当然使用这个模式的时候,我们还要注意很多细节,这个是我们必须面对的,比如我们怎么实现View和ViewModel关联、View和 ViewModel如何通信、ViewModel与ViewModel如何交互、ViewModel和Model之间的弱关联、怎样用 Attached Behavior实现特定命令操作、怎样弹出UI、怎样实现导航、Validation的自定义设置、异步调用、延迟加载、性能优化、与传统技术的交互等 等问题。
八. WPF团队协作
前面我们讲了WPF的开发模式,针对不同的开发模式,团队协作也会有一些具体的改变,不管是MVC、MVP还是MVVM,无疑都强调的是 Presentation,所以我们的域模型和底层操作都不会有所变化,或者严格一点的说是只能影响到服务层/域模型之上的操作!如果不考虑多系统分布 式、ESB及SOA体系,就可以分成以下六种角色:
-
专业美工人员:整个系统的基调与样式、页面布局图、页面效果图、页面的样式与颜色、常用按钮图标、常用图标图片等等。
-
XAML人员:Style,Template,Trigger,Resource用XAML代码书写,另外强调和美工及ViewModel人员的交互与合作。
-
ViewModel :主要封装领域模型暴露的接口,然后提供给View,所以这里强调UI和领域模型的一个适配作用。
-
领域模型(核心):应用程序的核心,必须投入大量精力,按照面向对象的分析和设计 (OOAD) 最佳做法进行设计同时按照OOP进行开发。
-
框架+常用功能开发人员:这里就包括MVVM框架的开发、维护以及扩展,同时还包括数据底层访问、日志、异常、常用功能等。
-
数据库开发和管理人员:数据库库表的建立及维护、数据库脚本的创建及维护、数据库优化以及日常的数据操作问题。
当然在开发中,这六种角色也并不是完全分离的,可以根据具体需求进行调整,同时也可以根据项目的功能划分模块,总之选择项目最合适的协作方式就行。
九. 了解并使用MVVM框架
1,到底有哪些开源MVVM框架?
前面介绍了WPF的基本概念和一些相关知识,我们了解到开发WPF应用程序可以使用现成的框架和模式,最为合适的莫过于时下正热的MVVM模式,所以这里我们也列出针对MVVM模式的已有开源框架:
图3
上面除了WPFToolKit和MEF之外都是一些常用的MVVM框架,连带自己开发的一共是八个,所以自己也取了一个响亮的名字——MVVM 八大框架!圣殿骑士本人实际项目中只用到了三个框架,之前WPF使用过MVVM Helpers,在Silverlight项目当中用过MVVMLight+MEF,后来就一直使用自己开发的框架,其他框架也研究了很长时间,但都是为 了开发MVVM框架借鉴之用。框架虽然众多,但万变不离其宗,通用功能如下:
- 1,Model、View 和 ViewModel之间的关系:View和ViewModel如何关联起来(IOC)以及如何通信(通常采用Message),ViewModel和Model之间的弱关联(通常采用接口或者简单注入)。
- 2,事件驱动模式在MVVM模式采用Command和Attached Behaviors的形式。
- 3,属性及ViewModel的NotifyPropertyChanged处理。
- 4,提供完整的单元测试,这也是保证框架的稳定性和维护性的保证。
也许有一些朋友会问我为什么要研究这么多框架,其实做项目只需要认真研究并实践其中一个就行,研究它们的原因则主要归功于自己开发MVVM框架的需要。下面就让我们来看一下具体有哪些MVVM的开源框架(具体到每一个框架后面有时间再阐述,一篇文章写得确实很累):
2,最强大且功能最多的组合框架——Prism
下载地址:http://compositewpf.codeplex.com/
开发者:微软patterns & practices团队
是否支持Silverlight:是
学习资料:Composite Application Guidance for WPF and Silverlight - May 2010.chm以及Quickstarts和StockTraderRI等。
源码截图如下:
图4
Prism——之前又叫Composite Application Guidance for WPF and Silverlight,它是构建复杂的基于WPF/Silverlight企业级应用的主流框架。Prism中有几个比较重要的概念:
- 1,BootStrapper:应用程序切入点,继承Prism的UnityContainer或MEF提供的MefUnityContainer,为系统提供一个容器。
- 2,Shell:它是一个外壳,通过UI元素和Region布局页面。 它是应用程序的顶级窗口,显示的内容一般就由View来填充,Shell本身并不知道它包含了哪些内容,所以功能则是由各个Module来具体提供。
- 3,View:它等同于MVP模式、MVVM模式中的View。可以通过IRegionManager注入到Region中。
- 4,Module:可以把一个大项目拆分开来,每一个Module都包含View、数据、模型,主要用于实现复杂业务操作。
- 5,IModuleManager:主要用于管理模块加载,可以实现动态加载。
- 6,IEventAggregator:事件处理接口,实现订阅和发布模式,这也是MVVM框架的一般做法。
Prism是一个比较庞大的组合框架,4.0引入MEF及功能调整以后变得更加强大了,现在可以说是组合框架和应用框架的统一体,而且是微软团队的力量,所以选它是值得保证的。
3,最强大且功能最多的应用框架——Caliburn
下载地址:http://caliburn.codeplex.com/
开发者:Rob Eisenberg
是否支持Silverlight:是
学习资料:我主要参考项目实例、源码、单元测试用例、国外一些博客和社区。
源码截图如下:
图5
Caliburn中有几个比较重要的概念:
- 1,在Actions基础上的Commands带有很多功能,其中包括多参数、过滤操作以及异步调用。
- 2,窗体和控件的生命周期事件也处理得比较好(包括activation、deactivation、shutdown等)。
- 3,不管是整个框架还是基于这个框架的应用程序的可测性都比较好。
- 4,提供了很多常用功能,这些在项目当中都比较有用。
- 5,除了支持MVVM模式之外,还很好的支持MVP模式以及其他的一些变种模式。
- 6,强大的依赖注入框架以及AOP框架,这里可以灵活选用其中一种。
Caliburn是一个非常强大的MVVM应用框架,对很多功能都提供了灵活且多种实现,不论是项目使用还是研究代码,感觉都受益颇多。
4,轻量级且适用的MVVMLight
下载地址:http://mvvmlight.codeplex.com/
开发者:Laurent Bugnion
是否支持Silverlight:是
学习资料:除了online documentation,我主要参考项目实例、源码、单元测试用例、国外一些博客和社区。另外这三篇文章非常不错,用MVVMLight开发了一个比较完整的Silverlight企业项目
- Part 1 - Introduction, Installation, and General Application Design Topics
- Part 2 - MVVM Light Topics
- Part 3 - Custom Authentication, Reset Password and User Maintenance
源码截图如下:
图6
MVVMLight中有几个比较重要的概念:
- 1,RelayCommand:通过对Command进行封装,使得MVVM模式在WPF和Silverlight上更加容易。你只需要在 ViewModel中定义好各个RelayCommand,然后在View中通过Command来绑定ViewModel中定义好的 RelayCommand,就可以实现像WinForm、ASP.NET事件一样的效果,只不过这里是解除了UI和逻辑的强耦合。
- 2,Messager:MVVMLight中的Messager作用比较大,前面讲了MVVM模式解除了ViewModel和View的强引用,那 么它们如何来进行交互呢?就是靠它来让ViewModel和View来进行通信的。一般我们会定义一个静态AppMessages类来作为通用的一个通信 类,原理就是发布订阅模式。
- 3,EventToCommand:这里就比较类似于附加行为的概念,是在MVVM Light Toolkit V3中开始引入的概念。
- 4,ICleanup接口:当显示某个View时,需要先调用Cleanup方法清除数据,这也是由于ViewModel和View的耦合隔离产生的一些必要操作。
MVVMLight是一个非常好用的MVVM框架,提供了VS和Blend的模板及智能感知。它结合MEF使用真的感觉很轻量级且高效,而且提 供了WPF和Silverlight的支持,尤其在Silverlight的支持上比较好,所以一般选择轻量级的Silverlight MVVM模式,它比较被看好。
5,功能齐备且易用的MVVM Helpers
下载地址:http://mvvmhelpers.codeplex.com/
开发者:Mark Smith
是否支持Silverlight:否
学习资料:http://www.julmar.com/blog/mark/以及提供的实例、源码及测试用例。
源码截图如下:
图7
MVVM Helpers又叫JulMar MVVM Helpers + Behaviors,其中有几个比较重要的概念:
- 1,提供了MVVM模式的基本功能,包括ViewModel、View及Model之间的隔离,另外还提供了一些常用功能。
- 2,ViewModel的创建使用标签的形式注入,现在也可以引入MEF。
- 3,IOC/DI的支持,属性都有验证机制,Wait Cursor的支持,当使用完viewmodel之后能及时释放,这样避免内存泄露。
- 4,提供了常用的Attached Behaviors支持。
- 5,消息机制的引入,避免强引用产生的耦合。
MVVM Helpers是一个非常适用的MVVM框架,尤其是提供了MVVM常用功能+MEF+Attached Behaviors,所以项目中的问题基本都能解决。
6,功能强大且轻巧的Cinch
下载地址:http://cinch.codeplex.com/
开发者:Sacha Barber
是否支持Silverlight:否
学习资料:http://sachabarber.net/以及提供的实例、源码及测试用例。
- A walkthrough of Cinch, and its internals - Part I
- A walkthrough of Cinch, and its internals - Part II
- How to develop ViewModels using Cinch
- How to Unit test ViewModels using Cinch app, including how to test Background work threads which may run within Cinch ViewModels
- A Demo app using Cinch
源码截图如下:
图8
如果仔细研究其代码,你会发现它和上面讲的MVVM Helpers有很多相似的代码,估计是相互参考了一番:-D。Cinch 中有几个比较重要的概念:
- 1,这个框架在没有MEF出现之前就已经实现了ViewModel和View之间的强引用隔离,它既没有一般IOC的配置,也没有IView来做中转,并且窗体和控件的生命周期事件也处理得比较好,所以在这方面来说是非常不错的。
- 2,提供了常用的Attached Behaviors支持,另外也提供了一些MVVM常用功能。
- 3,DI/IOC使用Unity实现,多线程的实现,避免系统出现不可预料的错误。
- 4,当使用完viewmodel之后能及时释放,这样避免内存泄露,验证机制的加入,常用导航实现。
- 5,消息机制的引入,避免强引用产生的耦合。
Cinch 是一个非常强大的框架,尤其是它比较着眼整个应用程序的搭建,所以也比较受到青睐。
7,功能简单且易扩展的MVVMFoundation
下载地址:http://mvvmfoundation.codeplex.com/
开发者:Josh Smith
是否支持Silverlight:否
学习资料:http://joshsmithonwpf.wordpress.com/以及提供的实例、源码及测试用例。
源码截图如下:
图9
MVVMFoundation中有几个比较重要的概念:
- 1,Messenger:这里主要用在各种不同的ViewModel之间通信(比如相互关联的ViewModel、主从ViewModel等),当然也可以扩展成ViewModel与View之间进行通信。
- 2,ObservableObject:这里相当于ViewModelBase的概念,每一个ViewModel继承自该类,调用完成之后立即释放,防止内存泄露。
- 3,PropertyObserver:主要是对INotifyPropertyChanged.PropertyChanged进行封装,这样封装可以精简代码,同时可以防止不当操作引起的内存泄露。
- 4,RelayCommand接口:封装command的声明,包括execution执行逻辑,可选的can-execute逻辑等。外部只需要实例化并Binding就可以简单使用。
MVVMFoundation是一个非常简单的MVVM框架,如果你觉得研究源码比较困难,就可以先从这个框架入手,代码简单而且精炼。
8,附加:支持插件式的依赖注入MEF
下载地址:http://mef.codeplex.com/
源码截图如下:
图10
9,如何充分利用这些框架
上面我们已经介绍了七大MVVM框架+支持插件式的依赖注入MEF,其实另外这三个框架WPF Application Framework (WAF)、Calcium、CoreMVVM(Basic MVVM framework)也很值得研究,由于时间和精力的关系,针对这三个框架圣殿骑士也没有进行仔细的剖析,只是粗略看了一下基本功能。
其他一些框架诸如Onyx、nRoute、Nito MVVM、Ocean、GoodLight就没有太多关注,有兴趣的朋友也可以选择其中某一个或多个框架作为研究和学习,不过还是推荐研究主流的框架,毕竟这些主流框架的开发团队和成熟度都比较强。
上面看到了这么多MVVM框架,那么我们应该怎么去学习和使用呢?简单来说可以归纳为以下几句话:
- 1,根据具体的项目选择适合的框架,团队和项目有大有小,所以得根据这些来选择具体的框架,其实终归来说,几个框架功能都比较类似。
- 2,框架不用研究太多,只要适用于项目就行,尤其是熟练使用并根据其提供的TDD测试代码追溯其原理。
- 3,框架不是万能的,对于某些应用和功能可以对框架扩展,这也开源最大的好处之一。
针对框架的研究,自己也总结了几点:
- 1,首先看框架的相关介绍,了解相关的背景、功能、架构图以及其他一些相关信息——认识了解。
- 2,根据介绍查看并调试框架所提供的实例——熟悉功能。
- 3,自己写一些相关的项目,主要是熟悉该框架,如果说要急于做项目,后面就可以把框架引入到项目当中——具体使用。
- 4,根据该框架提供的详细单元测试研究其源码,这也是我最喜欢研究这些开源框架的原因——原理剖析。
- 5,通过上面的步骤认真分析其原理及细节——准备重现。
- 6,自己也根据之前的思路重复开发这个框架,最好能用TDD——框架复原捷径。
上面我们谈了一些开源框架相关知识,下一步我们得自己开发一个MVVM框架,一方面是对知识的总结,另一方面也是对知识的再提炼,同时也能使自己的认识提升到另一个高度,紧接下文。
十. 自己开发MVVM框架
由于之前自己做了一套框架,但是还没有趋于完善,所以暂时不准备共享出来(主要是WPF和Silverlight版本更替比较频繁且没有加入模板及智能感知)。对于开发一套MVVM框架,具体需要做一下几个操作:
- 1,要能解决Model、View和ViewModel之间的强关联,这也是核心功能,尤其是View和ViewModel,不管是使用IOC Container还是MEF都行。
- 2,命令和附加事件的处理,对Command进行封装,满足多参数、方法过滤、泛型、异步回调等,对附加事件进行封装,使它像使用命令一样简便。
- 3,由于View和ViewModel是弱关联或者是无关联,如何让它们进行通信?这就需要加入Messenger机制。
- 4,前面引入了消息机制(一般是静态化处理),如何来管理、实例化、清除消息呢?这里得建立一套消息机制。
- 5,由于前面采用了弱关联或者无关联,并且引入了消息机制,所以需要对操作有日志记录,否则出了问题无法快速定位及追查原因。
- 6,如何统一管理ObservableObject、PropertyObserver等这些对象呢?所以得自己建立一套变更体系。
- 7,对常用功能及操作进行封装,提供一些常用类库以及UI Helper等。
总之,开发MVVM框架不能求全,只要适合项目就行,也不要想一次就能完善整个框架,在使用时不断根据需求扩展才是明智之举。另外附加三点开发MVVM框架心得:
- 1,充分借鉴其他开源框架,研究各个框架的不足和优势,然后把思想贯穿于自己的框架中,当然有些常用功能代码也可以直接借鉴过来。
- 2,对于这样一个比较庞大的框架,使用TDD+反复重构无疑会提高开发效率,同时也能提高框架的可维护性和稳定性,这也是团队使用的一个前提。
- 3,框架会使用一些常用设计模式,有了它们可以让框架更具有扩展性,同时也减少了开发成本、增加了可维护性。比如观察者模式(消息的发布、订阅、触 发)、中介者模式(直接通信的类转化为中间类来处理,隔离耦合)、外观模式(提供一个简单的接口出来,在内部进行大量的封装,这样就可以起到易用且功能强 大的目的)、装饰模式(原来已经稳定的功能模块,如果在不改变原有结构的基础上进行扩展,无疑这是一个很好的实践)等。
总结
上篇WPF企业内训全程实录(上)主 要讲解历史渊源、概念引入、基本阐述以及WPF的每个知识点。这篇主要主要围绕WPF开发模式、WPF团队协作和MVVM框架三个议题进行阐述。下篇将着 重强调结合其他技术共同打造WPF项目、相关性能优化、以及部署与更新问题,所以敬请期待!另外如果有不懂的地方也可以参考之前写的WPF 基础到企业应用系列,最后声明一下,由于圣殿骑士才识浅薄,所以以上观点只是个人的看法与心得,遗漏和错误之处也敬请海涵。怀着技术分享与交流的态度分享出来,希望各位多多指教!