天天看點

WPF企業内訓全程實錄(中)摘要章節綱要七. WPF開發模式八. WPF團隊協作九. 了解并使用MVVM架構十. 自己開發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開發模式(這裡通常所說的是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模式就是一個不錯的選擇,詳見如下架構圖:

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/mvvmModel_2_2.jpg"></a>

                                             圖1

  在MVVM模式中,你需要一個為View量身定制的model,那麼這個model實際上就是上圖ViewModel。ViewModel包含 所有UI所需要的接口、屬性和指令,這樣隻需要通過Binding使他們進行關聯,就可以使二者之間達到松散耦合,是以這樣一來,UI就可以由UI專業人 員用Design和Blend來實作(當然很多效果還是需要用傳統的制圖軟體,是以我們都稱這種想法叫理想狀态),代碼人員也可以專心寫他的邏輯和業務代 碼,是以這樣分工和協作變得更輕松、更愉快了。更漂亮的是View完全可以由(Unit/Automatic Test)所取代,是以單元測試也變得相對簡單。這對于我們的開發人員和測試人員無疑是一個很好的解脫,同時也提高了系統的可測性、穩定性和維護性。資料 綁定系統同時也提供了标準化的方式傳輸到視圖的錯誤驗證和輸入驗證(但是個人覺得不是很好用,是以我們在實際的項目當中會寫一套自己的驗證架構)。

講到這裡,我們這裡不得不引入下面這幅圖,我覺得它能闡述一些比較重要問題:

上面的這幅圖表達了幾個概念:

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的開發模式,針對不同的開發模式,團隊協作也會有一些具體的改變,不管是MVC、MVP還是MVVM,無疑都強調的是 Presentation,是以我們的域模型和底層操作都不會有所變化,或者嚴格一點的說是隻能影響到服務層/域模型之上的操作!如果不考慮多系統分布 式、ESB及SOA體系,就可以分成以下六種角色:

專業美勞工員:整個系統的基調與樣式、頁面布局圖、頁面效果圖、頁面的樣式與顔色、常用按鈕圖示、常用圖示圖檔等等。

XAML人員:Style,Template,Trigger,Resource用XAML代碼書寫,另外強調和美工及ViewModel人員的互動與合作。

ViewModel :主要封裝領域模型暴露的接口,然後提供給View,是以這裡強調UI和領域模型的一個适配作用。

領域模型(核心):應用程式的核心,必須投入大量精力,按照面向對象的分析和設計 (OOAD) 最佳做法進行設計同時按照OOP進行開發。

架構+常用功能開發人員:這裡就包括MVVM架構的開發、維護以及擴充,同時還包括資料底層通路、日志、異常、常用功能等。

資料庫開發和管理人員:資料庫庫表的建立及維護、資料庫腳本的建立及維護、資料庫優化以及日常的資料操作問題。

當然在開發中,這六種角色也并不是完全分離的,可以根據具體需求進行調整,同時也可以根據項目的功能劃分子產品,總之選擇項目最合适的協作方式就行。

  前面介紹了WPF的基本概念和一些相關知識,我們了解到開發WPF應用程式可以使用現成的架構和模式,最為合适的莫過于時下正熱的MVVM模式,是以這裡我們也列出針對MVVM模式的已有開源架構:

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/2010-10-31%2022-51-52_2.png"></a>

                                             圖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的開源架構(具體到每一個架構後面有時間再闡述,一篇文章寫得确實很累):

開發者:微軟patterns &amp; 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及功能調整以後變得更加強大了,現在可以說是組合架構和應用架構的統一體,而且是微軟團隊的力量,是以選它是值得保證的。

學習資料:我主要參考項目執行個體、源碼、單元測試用例、國外一些部落格和社群。

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/2010-10-31%2022-50-51_2.png"></a>

                                             圖5

Caliburn中有幾個比較重要的概念:

1,在Actions基礎上的Commands帶有很多功能,其中包括多參數、過濾操作以及異步調用。 2,窗體和控件的生命周期事件也處理得比較好(包括activation、deactivation、shutdown等)。 3,不管是整個架構還是基于這個架構的應用程式的可測性都比較好。 4,提供了很多常用功能,這些在項目當中都比較有用。 5,除了支援MVVM模式之外,還很好的支援MVP模式以及其他的一些變種模式。 6,強大的依賴注入架構以及AOP架構,這裡可以靈活選用其中一種。

Caliburn是一個非常強大的MVVM應用架構,對很多功能都提供了靈活且多種實作,不論是項目使用還是研究代碼,感覺都受益頗多。

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/2010-10-21%2016-22-04_2.png"></a>

                                             圖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模式,它比較被看好。

是否支援Silverlight:否

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/2010-10-21%2016-25-14_4.png"></a>

                                             圖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,是以項目中的問題基本都能解決。

<a href="http://www.codeproject.com/KB/WPF/CinchII.aspx">A walkthrough of Cinch, and its internals - Part I</a>

<a href="http://www.codeproject.com/KB/WPF/CinchIII.aspx">A walkthrough of Cinch, and its internals - Part II</a>

<a href="http://www.codeproject.com/KB/WPF/CinchIV.aspx">How to develop ViewModels using Cinch</a>

<a href="http://www.codeproject.com/KB/WPF/CinchV.aspx">How to Unit test ViewModels using Cinch app, including how to test Background work threads which may run within Cinch ViewModels</a>

<a href="http://www.codeproject.com/KB/WPF/CinchVI.aspx">A Demo app using Cinch</a>

<a href="http://images.cnblogs.com/cnblogs_com/KnightsWarrior/WindowsLiveWriter/f48594f12231_11135/2010-10-21%2016-34-31_2.png"></a>

                                             圖8

如果仔細研究其代碼,你會發現它和上面講的MVVM Helpers有很多相似的代碼,估計是互相參考了一番:-D。Cinch 中有幾個比較重要的概念:

1,這個架構在沒有MEF出現之前就已經實作了ViewModel和View之間的強引用隔離,它既沒有一般IOC的配置,也沒有IView來做中轉,并且窗體和控件的生命周期事件也處理得比較好,是以在這方面來說是非常不錯的。 2,提供了常用的Attached Behaviors支援,另外也提供了一些MVVM常用功能。 3,DI/IOC使用Unity實作,多線程的實作,避免系統出現不可預料的錯誤。 4,當使用完viewmodel之後能及時釋放,這樣避免記憶體洩露,驗證機制的加入,常用導航實作。

Cinch 是一個非常強大的架構,尤其是它比較着眼整個應用程式的搭建,是以也比較受到青睐。

                                             圖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架構,如果你覺得研究源碼比較困難,就可以先從這個架構入手,代碼簡單而且精煉。

                                             圖10

上面看到了這麼多MVVM架構,那麼我們應該怎麼去學習和使用呢?簡單來說可以歸納為以下幾句話:

1,根據具體的項目選擇适合的架構,團隊和項目有大有小,是以得根據這些來選擇具體的架構,其實終歸來說,幾個架構功能都比較類似。 2,架構不用研究太多,隻要适用于項目就行,尤其是熟練使用并根據其提供的TDD測試代碼追溯其原理。 3,架構不是萬能的,對于某些應用和功能可以對架構擴充,這也開源最大的好處之一。

針對架構的研究,自己也總結了幾點:

1,首先看架構的相關介紹,了解相關的背景、功能、架構圖以及其他一些相關資訊——認識了解。 2,根據介紹檢視并調試架構所提供的執行個體——熟悉功能。 3,自己寫一些相關的項目,主要是熟悉該架構,如果說要急于做項目,後面就可以把架構引入到項目當中——具體使用。 4,根據該架構提供的詳細單元測試研究其源碼,這也是我最喜歡研究這些開源架構的原因——原理剖析。 5,通過上面的步驟認真分析其原理及細節——準備重制。 6,自己也根據之前的思路重複開發這個架構,最好能用TDD——架構複原捷徑。

  上面我們談了一些開源架構相關知識,下一步我們得自己開發一個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,架構會使用一些常用設計模式,有了它們可以讓架構更具有擴充性,同時也減少了開發成本、增加了可維護性。比如觀察者模式(消息的釋出、訂閱、觸 發)、中介者模式(直接通信的類轉化為中間類來處理,隔離耦合)、外觀模式(提供一個簡單的接口出來,在内部進行大量的封裝,這樣就可以起到易用且功能強 大的目的)、裝飾模式(原來已經穩定的功能子產品,如果在不改變原有結構的基礎上進行擴充,無疑這是一個很好的實踐)等。

本文轉自KnightsWarrior51CTO部落格,原文連結:http://blog.51cto.com/knightswarrior/414347 ,如需轉載請自行聯系原作者