2013-01-09 62 views
6

我已閱讀了幾篇關於MVVM模式的文章,教程和博客文章。但有一件事我不明白。取三個「層次」:MVVM中的模型是什麼?

  • 模型
  • 查看
  • 視圖模型

據我明白MVVM模型包含的「原始」數據,例如在Student類的情況下的名稱和地址。視圖模型向視圖提供代表模型數據的屬性。

例在視圖模型

public string Name { 
get { return model.Name; } 
set { model.Name = value; } 
} 

實例屬性爲模型

private string name; 

public string Name { 
get { return name; } 
set { name = value; } 
} 

這聽起來有點傻,但不這樣創建一個冗餘?爲什麼我必須在模型和視圖模型中保留名稱?爲什麼不應該完全在視圖模型上處理名稱?

+1

順便提一下,問題很簡單:清晰,簡潔幷包含示例代碼。 – JDB

回答

5

在這樣一個簡單的例子中,這個答案是肯定的(這是不合理的冗餘)。但是,據推測,一個頁面將包含的不僅僅是一個單一的模型對象。您可能擁有頁面狀態以及必須全部跟蹤的多個其他模型對象。這是在ViewModel中完成的。

例如,您可能有關於狀態欄中顯示的已登錄用戶的附加信息,以及運行檢測文本文件更改的服務。

您可能還有一個用於編輯Student對象的窗體。如果您打算驗證這些更改,那麼在修改完成之前,您不希望直接編輯Student對象。在這種情況下,ViewModel可以充當臨時存儲位置。

關於上述內容的注意事項:在模型中進行驗證並不少見,但即使如此,您仍然希望用戶能夠在編輯表單的過程中輸入無效值。例如,如果您的模型在字段中不允許零長度值,您仍然希望使用戶能夠刪除該值,移動到另一個字段(例如,複製它),然後返回到字段並完成編輯(粘貼)。如果你直接綁定到模型,那麼你的驗證邏輯可能不會處理這個「中間」,「尚未完成」的狀態,只要你願意。例如,您可能不想在驗證錯誤完成後點擊「保存」來提醒用戶。

您也可能在ViewModel中有Command對象來處理按鈕點擊等。這些將是模型中無用的域特定對象。

當您需要過濾或以某種方式暫時「修改」模型對象以獲得屏幕上的某些內容時,ViewModels也很有用。例如,您可能想要顯示系統中所有用戶的列表以及其中前十名執行者的實時列表(每10秒更新一次)。或者您可能想要顯示報告列表和顯示整體使用率的圖表等。在ViewModel中將過濾,排序和自定義數據。

該模型,另一方面,通常是儘可能純。理想情況下,您只需要POCOs(通常)模擬永久存儲(數據庫或您有什麼)中的內容。如果您的持久存儲具有FirstName和LastName字段,那麼您的Model也是如此。只有在你的ViewModel中,你可以將它們組合起來以得到一個Name字段(根據視圖的需要,可以是「First Last」或「Last,First」)。

例如:在MVVM

namespace Model 
{ 
    public class Student 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 

    public class Class 
    { 
     public string Name { get; set; } 
     public float Score { get; set; } 
    } 
} 

namespace ViewModel 
{ 
    public class EditStudentRecordViewModel 
    { 
     private Model.Student _student; 
     private IEnumerable<Model.Class> _studentClasses; 

     /* Bind your View to these fields: */ 
     public string FullName 
     { 
      return _student.LastName + ", " + _student.FirstName; 
     } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public IEnumerable<Model.Class> PassingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score >= 78); 
      } 
     } 

     public IEnumerable<Model.Class> FailingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score < 78); 
      } 
     } 

     public void Save() 
     { 
      List<string> l_validationErrors = new List<string>(); 
      if (string.IsNullOrEmpty(this.FirstName)) 
       l_validationErrors.Add("First Name must not be empty."); 
      if (string.IsNullOrEmpty(this.LastName)) 
       l_validationErrors.Add("Last Name must not be empty."); 

      if (l_validationErrors.Any()) 
       return; 

      _student.FirstName = this.FirstName; 
      _student.LastName = this.LastName; 
      Model.Utilities.SaveStudent(_student); 
     } 
    } 
} 
5

該模型是包含您的業務邏輯的對象圖。

這就是你持有的行爲(驗證,計算等)。

ViewModel是模擬UI及其交互的東西。

這些是不同的,並且存在不同的原因 - 模式的要點是將顯示邏輯與VVM(View和ViewModel)分開,並將業務邏輯完全分開。

0

模型是完全一樣在MVP或Model2的MVC。它是MVC啓發模式的一部分,不受主題變化的影響。

模型是包含存儲庫,工作單元,域/模型對象,數據映射器,服務和一些其他結構的圖層。他們結合在一起創建了模型層,其中包含特定應用程序的所有域業務邏輯。

模型不是任何單個實例。否則任何人都會對你產生滿足感。

當您無法修改模型層或視圖實例,或者兩者皆有時,MVVM設計的特定用例就是情況。

P.S.但是,如果您按照ASP.NET MVC文檔使用ViewModel實例,那麼您實際上並未使用MVVM。它僅僅是Model2 MVC,其中有不同名稱的東西(其中「viewmodels」實際上是視圖,「views」是模板)。當他們將類似Rails的架構作爲「MVC」銷售時,他們有點不爽。

4

視圖模型是在那裏你會跟蹤特定於該視圖和沒有必要的模型屬性。

讓我們把你的模型,假設它叫做Person

然後創建一個名爲PersonViewModelPerson視圖模型,它看起來像這樣:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 
} 

(請注意,你可能不希望公開這直接與示範,但那是另一回事)

現在讓我們假設您在視圖中有一個按鈕,用於保存Person實例。爲了提供更好的用戶體驗(UX),只有在模型實際發生更改時才需要啓用該按鈕。所以你實現對PersonINotifyPropertyChanged interface

public class Person : INotifyPropertyChanged 
{ 
    ... 

現在,你可以Person其中Enabled財產的保存按鈕將綁定到暴露HasUnsavedChanges屬性,但這種邏輯有什麼到與該人做什麼。

這是視圖模型進來時你會在視圖模型定義這個視圖特定的屬性,像這樣:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 

    public bool HasUnsavedChanges { get; set; } 
} 

然後,您的視圖模型將訂閱的的PropertyChanged eventINotifyPropertyChanged界面,並在視圖模型上切換HasUnsavedChanges屬性。

然後,如果綁定設置正確,當您的模型發生任何更改時,保存按鈕將啓用/禁用,但您的模型沒有任何邏輯將其綁定到視圖。

請注意,您還必須在視圖模型上實現INotifyPropertyChanged,以及在視圖模型發生更改時視圖纔會選取。

此外,該點作爲一個橋樑來包含不屬於模型的模型屬性和視圖屬性組合的邏輯。

1

我一直將模型視爲應用程序的「構建模塊」。它們通常是自包含的類,具有一些屬性,並且可能僅對其自己的屬性進行一些基本的驗證或邏輯。

另一方面,查看模型是我的實際應用程序類,最終在構建和運行應用程序時使用「構建塊」(模型)。他們不喜歡的東西執行先進的驗證,過程的命令,處理事件,任何種類的業務邏輯等

應當注意的是,你不暴露你的模型的屬性在你的視圖模型就像你在有你的示例代碼。這樣做是因爲「模型層」與「視圖」層完全分離,因此將「整個模型」公開給視圖也是完全可以接受的。這是我通常在大多數小型項目中使用的原因,因爲它簡單並且沒有代碼重複。

public MyModel CurrentModel 
{ 
    get { return _model; } 
    set 
    { 
     if (_model != value) 
     { 
      _model = value; 
      RaisePropertyChanged("CurrentModel"); 
     } 
    } 
} 

但是,如果有其中只從模式中的一些特性需要在查看情況,或者如果項目足夠大,我會希望保持層完全分離,然後我暴露我的模特通過ViewModel的視圖屬性,就像你在示例代碼中一樣。