MVVM教程

 1.MVVM設計模式簡介

 

     MVVM的設計模式最早於2005年由微軟的WPF和Silverlight架構師John Gossman在他的博客中提到。以下是這篇文章的鏈接:

     http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx

     MVVM設計模式基於MVC這種將UI和邏輯分離的結構思想。傳統的.NET平臺下軟件開發如ASP.NET和WPF/Silverlight大多數是基於CodeBehind這樣的方式,我們往往將所有的代碼全部寫在後臺代碼文件中,例如UI操作,業務邏輯操作,IO,數據服務的調用等等。這雖然表面上有利於“開發效率”,實際上項目結構不清晰,各個模塊之間緊密耦合,不利於擴展,不利於測試。

     MV-X的思想,爲.NET平臺下的架構提供一種很好的實踐。使我們可以構建更利於擴展,結構清晰,職責分明,易測試的軟件項目。

     但是目前MVVM模式還沒有一個標準的實踐,微軟也還沒有給出相對標準的方案。目前社區討論的主要是MVVM的思想。在實際開發過程中形成了幾種不同的風格。其中以Josh Smith的文章影響比較大:

     http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

     本篇提到的也主要是參考John Smith的思想。

2.採用MVVM設計模式的好處

    

     在Silverlight或者WPF中採用MVVM的架構可以獲得以下好處:

     1. 項目可測試更高,從而可以執行單元測試

     2. 將UI和業務的設計完全分開,View和UnitTest只是ViewModel的兩個不同形式的消費者

     3. 有助於我們區別並哪些是UI操作,哪些是業務操作,而不是將他們全混在CodeBehind中

     3.項目結構介紹

     以下是示例項目的結構截圖:

vs

以下是各模塊之間的聯繫:

org

 

4.WpfMVVMSample.Foundation

     提供一些基礎類定義。

5.Model的職責

    

     Model主要提供基礎實體的屬性以及每個屬性的驗證邏輯。

     Model不包含數據的調用,但是可以包含簡單的非數據調用的操作,如產生序列號或者合併字段。

     對於WCF產生的客戶端代理類,Models中應有與之相對應的類結構定義。

     Model不依賴於任何項目。

6.IService和Services以及ServiceTest

     IService是所有網絡數據服務或者IO操作的服務接口。

     IService中的數據訪問方式以異步爲主,見參考示例。

     Service是真實的數據服務訪問類,是IService的實現。ServiceTest是用於測試ViewModel的IService的實現

7.ViewModel的職責

    

     ViewModel是MVVM架構中最重要的部分,ViewModel中包含屬性,命令,方法,事件,屬性驗證等邏輯。爲了與View以及Model更好的交互來滿足MVVM架構,ViewModel的設計需要注意一些事項或者約束:

    ViewModel的屬性:ViewModel的屬性是View數據的來源。這些屬性可由三部分組成:

     一部分是Model的複製屬性。

    另一部分用於控制UI狀態。例如一個彈出窗口的控件可能有一個IsClose的屬性,當操作完成時可以通過這個屬性更改通知View做相應的UI變換或者後面提到的事件通知。

    第三部分是一些方法的參數,可以將這些方法的參數設置成相應的屬性綁定到View中的某個控件,然後在執行方法的時候獲取這些屬性,所以一般方法不含參數。

     ViewModel的命令:ViewModel中的命令用於接受View的用戶輸入,並做相應的處理。我們也可以通過方法實現相同的功能。

     ViewModel的事件: ViewModel中的事件主要用來通知View做相應的UI變換。它一般在一個處理完成之後觸發,隨後需要View做出相應的非業務的操作。所以一般ViewModel中的事件的訂閱者只是View,除非其他自定義的非View類之間的交互。

     ViewModel的方法:有些事件是沒有直接提供命令調用的,如自定義的事件。這時候我們可以通過CallMethodAction來調用ViewModel中的方法來完成相應的操作。

8.View及Codebehind

     View中使用Command:View中的Button等控件可以直接綁定Command屬性調用ViewModel中的Command

     View中使用CallMethodAction :一些不支持Command的控件,可以用一個CallMethodAction觸發器來執行ViewModel中的方法。注意的是方法當中往往包含一些參數,這些參數一般可以通過給ViewModel設置相應的屬性來綁定到相關的輸入控件,如TextBox。

     View中使用DataTrigger:除了模型屬性,還有一部分是狀態屬性,這往往是ViewModel通過屬性更改的方式通知View做出相關的UI操作,例如觸發一段動畫,或者切換控件狀態等等。這個時候可以使用一些觸發器,當狀態值不同時做出相應的UI變換。

    View的CodeBehind中初始化子View的ViewModel上下文:View一般由父View調用,所以View的ViewModel一般由父View來初始化。比如當點擊人脈按鈕,需要顯示人脈的View的時候,就由主框架初始化人脈的ViewModel,並顯示人脈的View。

     View的CodeBehind中訂閱子View的UI事件:除了通過狀態屬性的變更觸發View中的觸發器,看一種選擇是在View的CodeBehind中訂閱ViewModel的UI事件。

9.View及ViewModel交互模式總結

由以上解析我們可以總結出View和ViewModel的交互模式:

1. 父View在CodeBehind中初始化子ViewModel

2. 父View在CodeBehind中訂閱子ViewModel的UI事件

3. 父View將子ViewModel賦值給子View的DataContext,並顯示子View

4. 父View調用子ViewModel獲取數據的方法,子ViewModel調用數據服務獲取數據

5. ViewModel的數據通過Binding傳遞給View

6. View接受用戶輸入,並通過Command或者CallMethodAction交給ViewModel做業務處理

7. ViewModel處理完成之後觸發UI事件或者更改狀態屬性通知父View

8. 父View做出View變換至新的界面

10. 依賴注入

ViewModel的職責是提供數據給View,並調用底層的數據服務。

爲了解除ViewModel和BP的耦合,增加一層IService的接口定義,這也使得我們可以構造不同的IService實現來測試ViewModel。

但是View 在使用ViewModel的時候,ViewModel必須要使用IService對象,所以這裏採用依賴注入。通過依賴注入來完全解除View以及ViewModel對於Service的依賴。

示例項目源代碼下載:

http://files.cnblogs.com/hielvis/WpfMVVMSample.rar

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章