ASP.NET MVC中的'RenderPartial()'方法提供了非常低级别的功能。它没有提供,也没有尝试提供真正的“子控制器”模型*。
我通过'RenderPartial()'渲染了越来越多的控件。它们分为三大类:
1)直接控制 特定页面的后代 使用该页面的模型
2)直接控制 特定页面的后代 使用该页面的模型 additional key of some type。 想想实施 '的DataRepeater'。
3)代表无关的控件 它们出现的页面的功能 上。这可能是一个 横幅旋转器,反馈表, 商店定位器,邮件列表注册。 关键是它并不关心 它放在哪个页面上。
由于ViewData
模型的工作方式,每个请求只存在一个模型对象 - 也就是说,子控件需要的任何内容都必须出现在页面模型中。
最终,MVC团队希望能够推出真正的“子控制器”模型,但在此之前,我只是在主控页面模型中添加任何内容,孩子控制也需要。
在上面的(3)的情况下,这意味着我的'ProductModel'模型可能必须包含'MailingListSignup'模型的字段。显然这并不理想,但我已经接受了与当前框架的最佳妥协 - 并且最不可能'关闭未来的子控制器模型的任何一扇门。
控制器应负责获取模型的数据,因为模型实际上应该是一个愚蠢的数据结构,不知道它从何处获取数据。但我不希望控制器必须在几个不同的地方创建模型。
我开始做的是创建一个工厂来创建模型。该工厂由控制器调用(模型不了解工厂)。
public static class JoinMailingListModelFactory {
public static JoinMailingListModel CreateJoinMailingListModel() {
return new JoinMailingListModel()
{
MailingLists = MailingListCache.GetPartnerMailingLists();
};
}
}
所以我的实际问题是,同样问题的其他人如何实际创建模型。什么是未来与新MVC功能兼容的最佳方法?
RenderAction()
存在一些我不会在这里遇到的问题 - 尤其是它只存在于MVCContrib中而不会出现在ASP.NET-MVC的RTM版本中。导致sufficent problems的其他问题我选择不使用它。所以我们现在假装只有RenderPartial()
存在 - 或者至少那就是我决定使用的那些。答案 0 :(得分:5)
不是将MailingListSignup
之类的内容添加为ProductModel
的属性,而是将其封装在类似ProductViewModel
的类中的同一级别,如下所示:
public class ProductViewModel() {
public ProductModel productModel;
public MailingListSignup signup;
}
然后将您的视图强类型化为ProductViewModel
类。您可以致电ProductModel
访问Model.productModel
,然后使用Model.signup
访问注册课程。
这是对Fowler的“演示模型”(http://martinfowler.com/eaaDev/PresentationModel.html)的宽松解释,但我看到它被一些微软开发者使用,例如Rob Conery和Stephen Walther。
答案 1 :(得分:2)
我在这种情况下看到的一种方法是使用动作过滤器来填充局部视图的数据 - 即子类ActionFilterAttribute
。在OnActionExecuting
中,将数据添加到ViewData中。然后你只需要用过滤器装饰使用部分视图的不同动作。
答案 2 :(得分:1)
我使用了RenderPartial重载,让你指定一个新的ViewData和Model:
如果您查看MVC源代码的上一个链接,以及以下内容(查找RenderPartialInternal方法):
您可以看到,如果基本上复制了您传递的viewdata,则创建一个新的Dictionary并设置要在控件中使用的Model。因此页面可以有一个Model,但是然后将不同的Model传递给子控件。
如果没有直接从主视图模型中引用子控件,您可以使用Marc Gravell提到的添加自定义逻辑的技巧。
答案 3 :(得分:0)
我尝试过的一种方法是使用带有接口的强类型局部视图。在大多数情况下,聚合的ViewModel是更好的方法,但我仍然希望分享这个。
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMailingListSignup>" %>
Viewmodel实现了接口
public class ProductViewModel:IMailingListSignup
这根本不完美,但解决了一些问题:您仍然可以轻松地将路线中的属性映射到模型。如果你有一个路由参数映射到MailingListSignup的属性,我不是shure。
您仍然遇到填充模型的问题。如果不迟到,我宁愿在OnActionExecuted中这样做。我不明白你如何在OnActionExecuting中填写模型。