2013-05-14 74 views
36

比方說,我有一個頁面,允許用戶的詳細信息的編輯,所以我有一個視圖模型是這樣的:ASP.NET MVC - 究竟是如何使用視圖模型

public class UserViewModel { 
    public string Username { get; set; } 
    public string Password { get; set; } 
    public int ManagerId { get; set; } 
    public string Category { get; set; } 
} 

所以我EditUser行動我能有這樣的回傳被模型綁定,然後我可以映射到域模型:

public ActionResult EditUser(UserViewModel user) { 
    ... 

然而,這顯示錶單的頁面也需要細節,如經理和分類的列表提供下拉菜單供那些領域。它也可能在側邊欄中顯示其他用戶的列表,以便您可以在正在編輯的不同用戶之間進行切換。

於是我有另一種看法型號:

public class ViewUserViewModel { 
    public UserViewModel EditingUser { get; set; } 
    public IEnumerable<SelectListItem> Managers { get; set; } 
    public IEnumerable<SelectListItem> Categories { get; set; } 
    public IEnumerable<SelectListItem> AllUsers { get; set; } 
} 

這是做了正確的方法是什麼?他們都是視圖模型嗎?如果是這樣,是否有我應該使用的命名約定,以便我可以區分類似模型的虛擬機和僅包含頁面數據的虛擬機?

我有這個錯誤嗎?

回答

20

我如何做到這一點的快捷方式:

  1. 爲每個單獨的ViewModel類窗體在頁面上,然後我用PartialViews渲染這些類爲@{Html.RenderPartial("PartialName", Model.PartialModel);}
  2. 如果頁面包含html metas之類的東西,我爲metas製作分隔類,並將其放在頁面的部分。
  3. 休息例如「我應該把它放在分開的班級嗎?」是你的判斷。

因此,例如,你有頁面有某種登錄/註冊欄或彈出任何。

public class SomePageViewModel 
{ 
    public RegisterBarVM Register { get; set; } 
    public LoginBarVM LoginBar { get; set; } 

    public MetasVM Metas { get; set; } 
    public string MaybePageTitle { get; set;} 
    public string MaybePageContent { get; set;} 

    [HiddenInput(DisplayValue = false)] 
    public int IdIfNeeded { get; set; } 

    public IEnumerable<SelectListItem> SomeItems {get; set;} 
    public string PickedItemId { get;set; } 
} 

public class RegisterBarVM 
{ 
    public string RegisterUsername {get;set;} 
    public string RegisterPassword {get;set;} 
    //... 
} 

public class LoginBarVM 
{ 
    public string LoginUserame {get;set;} 
    public string LoginPassword {get;set;} 
    //... 
} 

//cshtml 
@model yourClassesNamespace.SomePageViewModel 
@{ 
    Html.RenderPartial("LoginBar", Model.LoginBar); //form inside 
    Html.RenderPartial("RegisterBar", Model.RegisterBar); //form inside 

    using(Html.BeginForm()) 
    { 
     @Html.EditorFor(m => m.IdIfNeeded) 
     @Hmtl.EditorFor(m => m.MaybePageTitle) 
     @Hmtl.EditorFor(m => m.MaybePageContent) 

     @Hmtl.DropDownListFor(m => m.PickedItemId, new SelectList(Model.SomeItems)) 

     <input type="submit" value="Update" /> 
    } 
} 

@section Metas { 
    @{Html.RenderPartial("Meatas", Model.Metas} 
} 

關於編輯模板Brad Wilsons Blog,只是谷歌或查找有關顯示/編輯模板和HtmlHelpers棧資源。它們對構建一致的網站非常有用。

9

我個人比較喜歡把頁面所需的所有信息放在ViewModel中,因爲這是ViewModel的目的 - 爲View提供所有的數據。所以我的UserViewModel將包含Managers,CategoriesAllUsers的屬性,並且在將ViewModel傳遞到視圖之前,控制器將填充這些集合。

這實質上就是你所做的 - 它只是從等式中移除額外的ViewModel。

我也看到其他程序員使用ViewData將下拉列表發送到視圖,但我不喜歡,因爲ViewData不強類型,而ViewModel是。

93

「查看模型」只是一種模式。關於名稱沒有什麼不可思議的,但是通常任何類別被傳遞給視圖(無論是簡單地顯示數據還是用於表單提交的目的)都被稱爲「視圖模型」,並且給出諸如FooViewModelFooVM這樣的名稱以指示它是「視圖模型」模式的一部分。

我不想對你太過哲學,但我認爲對遊戲模式的一點參考將會有所幫助。 ASP.NET MVC顯然足以鼓勵MVC(模型 - 視圖 - 控制器)架構模型。在MVC中,模型是所有應用程序的商業邏輯的容器。 Controller負責處理請求,獲取模型,使用該模型呈現View並返回響應。這似乎是很多責任,但實際上框架處理幕後的大部分內容,所以控制器通常(而且應該)在代碼上非常輕。他們負責將所有東西連接起來的最低限度的功能。最後,視圖負責創建UI層,允許用戶與模型中的數據進行交互。它不是而是負責數據本身,也不應該是這樣(ViewData/ViewBag在這裏是一個非常大的違規,至少和開發人員在實踐中使用它的方式一樣)。

所以,這意味着你的應用程序邏輯的大部分應該在你的模型中,通常這是一件好事。但是,由於該模型是應用程序數據的避風港,因此通常會保留在數據庫或類似數據庫中。這會產生一些利益衝突,因爲您現在需要在應該保留哪些數據與僅存在用於顯示目的的數據之間開始平衡操作。

這就是視圖模型出現的地方。MVVM(模型 - 視圖 - 視圖模型)是一種與MVC有點平行的模式,它認識到單一模式到規則全部方法的固有問題。這裏我不會詳細討論,因爲MVC不使用這種模式。但是,大多數ASP.NET MVC開發人員已經選擇了MVVM的View Model。你實際上最終得到的是由數據庫支持的實體(傳統模型),然後通常是代表該實體處於各種狀態的許多不同視圖模型。這允許您的模型包含與持久性相關的業務邏輯,而視圖模型包含與顯示,創建和更新模型相關的業務邏輯。

我已經走了一段路,但多空是你所做的完全可以接受的。事實上,這是很好的做法。根據應用程序的需要創建儘可能多的視圖模型,並使用它們實際存儲視圖所需的數據和業務邏輯。 (這包括像SelectList既不控制器也不觀點應該需要知道如何爲下拉列表創建SelectList。)

+6

關於這個問題的最好解釋。你應該把它放在博客上! +1 – 2014-02-04 16:51:19

+0

你已經提到模型應該負責應用程序的業務邏輯。通過業務,您可能意味着所有的數據準備,查詢,過濾,投影一個模型到另一個模型,或者一個特定的ViewModel。然後這樣準備好的ViewModel被控制器傳遞給View。你如何做到這一點?你如何設計模型來做生意?你是否將所有控制器方法移動到表示視圖模型的類中?目前,我在控制器中有許多功能和「業務」,這些功能和操作完成所有的位和螺栓。謝謝 – Celdor 2015-07-31 10:29:47

+0

坦率地說,你不能在ASP.NET MVC中做到這一點。要真正理解我在說什麼,請在Ruby on Rails中構建一個示例應用程序。 RoR非常嚴格地遵守MVC模式,您將會看到他們的模型到底有多少。另一方面,ASP.NET MVC只是鬆散地遵守MVC。你「模型」將是實體類,視圖模型以及類似存儲庫或服務的某種組合。你應該儘量保持你的控制器精簡,你不能將所有邏輯移動到一個類中。 – 2015-07-31 18:19:59