2010-01-05 54 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

有一两件事似乎没有人提到的是,在最初的提问例如,它可能是有意义的创建视图出了一系列处理自己的功能区,而不是使一个大型视图模型儿童的行动中。这样,诸如未经批准的消息等组件可以被重用。

这也提供了更好的封装。

相关问题