2010-01-05 51 views
8

我的術語可能是在這裏,但基本上我試圖將多個數據模型傳遞給視圖。爲了幫助解決這個問題,請參考以下示例:發送到單個視圖實例的多個模型

假設我正在製作博客。當我登錄時,我希望主屏幕顯示所有未經批准的新評論的列表,以及最近註冊的用戶列表以及最近提交的博客帖子的列表。

我所見過的大多數討論都強烈建議您輸入視圖頁面,以便可以使用類似「return View(RecentComments)」的方法來調用視圖,並遍歷視圖中的註釋或者轉換數據模型,如「var NewUsers =(MembershipUserCollection)ViewData.Model「。我理想的做法是「正確的」,或者至少是一種「足夠正確」的方式來傳遞多個模型,同時保持適當的邏輯分離。

+0

*嘆*在事後,這是令人尷尬顯而易見。 – nathanchere 2012-01-16 04:57:28

回答

14

一種方法是創建一個新的類型,封裝模型數據的兩件:

public class MyBigViewData { 
    public SubData1 SubData1 { get; set; } 
    public SubData2 SubData2 { get; set; } 
} 

public class SubData1 { 
    ... more properties here ... 
} 

public class SubData2 { 
    ... more properties here ... 
} 

另一種方式是存儲爲強類型數據的「主」模型數據和存儲的其他數據視圖數據字典項:

ViewData["username"] = "joe"; // "other" data 
ViewData["something"] = "whatever"; // "other" data 
ViewData["subdata1"] = new SubData1(...); 
return View(myRealModelData); 

第二種方法的優點是你不需要做什麼特別可言:它的工作原理正確的開箱即用。

+0

我會做最簡單的事情,可以在這裏工作 - 所以將數據存儲在ViewData集合中。簡單。 – 2010-01-05 09:51:11

+1

這種方法存在的問題是,您可能最終會爲每個視圖增加視圖模型。有人認爲這是應該的,而在一個完美的世界我同意,但很多時候這種程度的定製超出了要求,實際上可以使項目更加難以理解。一種更快速,但**潛在風險的方法是,將下面的答案用於您的域實體。在某些環境中,這是不可接受的。例如,如果您將視圖開發外包,您可能不希望從視圖中使您的實體可見或可調用。 – 2010-01-11 04:00:52

3

不幸的是,實現傳遞多個對象的唯一方法是創建一個對象,其中包含兩個對象作爲字段/屬性,或者使用弱類型數組。

3

將多個模型傳遞給視圖的方法是創建我們稱之爲表單視圖模型的表單視圖模型,其中包含您的其他模型。

然後在您的視圖中,您可以將包含在您的表單視圖模型中的各個模型傳遞給負責在所述模型中呈現數據的部分視圖。

有意義嗎?

編輯

順便說一句:表單視圖模型只是一個類。這不是我的答案可能提出的特殊類型。

+2

這個詞是'ViewModel'他把它叫做'FormViewModel'因爲用戶在填寫了'Form'。如果你沒有填寫表單,那麼它只是一個'ViewModel',它允許強類型對象傳遞,而不是魔術字符串。 – 2010-01-05 16:01:00

+0

不錯的@George。 – griegs 2010-01-05 21:21:36

8

我在過去所做的是寫了一個類,其中包含我將在視圖上需要的兩個類的實例。

public class City{ 
public Mall TheMall; 
public School TheSchool; 
} 

那麼你的觀點會被強類型的城市,你會使用Model.TheMall.Property和Model.TheSchool.Property訪問你需要什麼

編輯

這是其他海報通過創建具有兩個對象作爲字段/屬性的對象的意思的示例

1

在處理大型ASP.NET MVC應用程序之後,我發現最有效的方法,同時最小化運行時轉換基於使用泛型來模仿視圖的嵌套結構。基本上看,獲得他們自己的數據類型。通常這些是域對象或包含元數據的域對象的集合。這些類型的通用版本在所有可能的母版頁上都可用,並且使用一個類型參數來定義與母版頁相關的數據。

public class Car { 
    // can be used as a model 
} 

public class CarCollection: Collection<Car> { 
    public BodyTypes BodyType {get;set;} 
    public Colors Color {get;set;} 
    // can also be used as a model 
} 

public interface ILayoutModel<TLayout> { 
    TLayout LayoutModel {get;set;} 
} 

public class CarView<TLayout>: Car, ILayoutModel<TLayout> { 
    // model that can be used with strongly-typed master page 
} 

public class CarCollection<TLayout> : CarCollection, ILayoutModel<TLayout> { 
    // model that can be used with strongly-typed master page 
} 

public class LayoutAData { 
    // model for LayoutA.master 
} 

public class LayoutBData { 
    // model for LayoutB.master 
} 

也有可能反轉一般的煩躁,但由於認爲決定了佈局,視圖數據應支配在我看來,佈局數據。 LayoutA.master將從ViewMasterPage<ILayoutModel<LayoutAData>>派生和LayoutB.master將從ViewMasterPage<ILayoutModel<LayoutBData>>派生。這使得視圖數據和佈局數據以一致,強類型和靈活的方式分開。

2

除了我的其他答案之外,另一種方法是在頁面指令中不強制使用視圖和母版頁,而是使用MVC Contrib中基於類型的基於ViewData的基本擴展。這些擴展基本上使用完全限定類型名稱作爲ViewData字典鍵。實際上,鍵入的好處與強類型頁面方法相同,就需要的視圖模型類的數量而言,類的開銷較少。然後在你的動作,你做

ViewData.Add<Car>(car); 
ViewData.Add<LayoutAData>(layoutAData); 

,並在意見你

<%= ViewData.Get<Car>().Color %> 

,並在母版頁你做

<%= ViewData.Get<LayoutAData>().Username %> 

你可以緩存這些獲取<>在內嵌調用這些觀點可以減少多次投射的費用。

1

創建一個對象,可以封裝你的其他對象是最好的一段路要走。否則,你會在控制器和視圖中遇到一堆醜陋的ViewData標籤。

1

有一兩件事似乎沒有人提到的是,在最初的提問例如,它可能是有意義的創建視圖出了一系列處理自己的功能區,而不是使一個大型視圖模型兒童的行動中。這樣,諸如未經批准的消息等組件可以被重用。

這也提供了更好的封裝。

相關問題