选项1-使用控制器的ViewData字典,在视图中通过icky基于字符串索引的方式进行类型转换,或者使用强类型自定义模型类以强类型方式传递该模型数据。
选项2-使用ViewData.Model,但我甚至不确定它的含义。
选项3-使用ViewPage.Model,在这种情况下,我不知道如何从控制器传递模型数据。
我看过很多帖子批评选项1和2,但我不明白为什么。在大多数情况下,这些帖子似乎高度推荐选项3。
您如何处理这个问题?是否有标准方法?
每个视图都应该有一个特定的模型。这有时需要更多的工作,因此人们使用像ViewData
这样的快捷方式,这种方法可以工作,但在我看来不够干净和类型安全,所以我更喜欢将所有内容放在视图的模型中。
然后,您可以使所有视图强类型化。这是一种非常干净的方法。然后在控制器中,您只需调用视图,如下所示:
YourViewModel model = new YourViewModel()
{
// initialize the data here
};
View(model);
然后在您的视图中,可以通过 ViewPage
Model
访问所有数据,并且它是类型安全的,同时也从控制器进行了强制执行。
来自评论的编辑:
如果不需要使用 ViewData
,您完全可以将视图所需的所有数据封装在一个模型中,就像您引用 ProductsListViewData
的示例一样。它只是一个包含要存储在 ViewData
中的所有项的模型。两种方式都可以,但当您将其封装在类中(优先使用方法,其中所有部分都是模型中的)时,所有组件都是强类型的。
ViewData
是一个通用容器,因此即使您可以将任何内容放入其中,但它不是类型安全的,因此不太“干净”。这取决于偏好和可维护性。只有选项1和3。您的选项2被误解了,实际上只是选项3。没有 ViewData.Model
,只有 ViewPage.Model
。
随着您的视图变得更加复杂,您可能希望考虑一种方法,即保留使用模型来支持输入字段,并使用ViewData来支持视图需要呈现的任何其他内容。
至少有几个论点支持这一点:
您有一个主页需要某些数据存在(例如标题中类似于StackOverflow用户信息的内容)。应用站点范围的ActionFilter可以轻松地在每个操作后将此信息填充到ViewData中。如果要将其放入模型中,则需要使站点中的每个其他模型都继承自基本模型(最初可能看起来不错,但很快就会变得复杂)。
当您验证已发布的表单时,如果存在验证错误,则可能需要将模型(带有无效字段)重新绑定回视图并显示验证消息。这是可以的,因为输入字段中的数据被发布并将绑定到模型,但是视图需要重新填充的任何其他数据呢?(例如下拉列表值、信息消息等)这些不会被发布回来,而且在“周围”发布回来的输入值上重新填充这些数据可能会变得混乱。通常更简单的方法是编写一个方法,用于将ViewData填充为视图数据。
根据我的经验,我发现这种方法很有效。
而且,在MVC3中,动态ViewModels意味着不再需要使用字符串索引!
我知道下面的答案可能存在争议,但这只是我喜欢的方式。
我会建议在处理简单数据任务时使用ViewData,在处理视图主要目的时使用Model。可以查看Rob Conery的ViewData帮助类,以使它们具有更强的类型感觉:
http://blog.wekeroad.com/2010/01/20/my-favorite-helpers-for-aspnet-mvc
对于绝大多数事情都使用模型会使你的项目膨胀成数百个模型,即使是实现最小的功能。我的意思是,如果你有一个用户设置页面,通常会将User-model传递到视图中,但如果你决定显示一些相关数据,比如与该用户相关的客户。你就会陷入以下解决方案:
或者
你可以这样做:ViewData["Customers"] = myRepo.GetCustomersRelatedTo(user); //或类似的方法。
并且(如果使用Robs helpers)在你的视图中:
<%= Html.RenderPartial("CustomerList", Html.ViewData("Customers")) %> 添加一个名为CustomerList的PartialView,它接受IEnumerable
在我看来,这是一个更清晰的解决方案,当然,你最终会得到一些魔术字符串,但除非有人向我展示一个没有任何魔术字符串的项目,否则我会坚持这种方法。
使用框架中提供的工具来完成工作。保持简单,让事情变得更容易... ;)