MVC - 多个强类型对象...在一个视图中

时间:2010-10-25 19:24:31

标签: asp.net-mvc templates

使用ASP.Net这么多年后,我仍在试图弄清楚如何使用MVC实现相同的结果。

我有一个带有控件的materpage,它是强类型的东西。当我导航到一个不同的强类型模型的视图...并单击按钮执行某些操作时,我得到“传递到字典中的模型项是Site.Models.RegisterModel'类型,但这个字典需要一个模型Site.Models.LogOnModel'“。

类型的项目

为了这个例子,我们可以使用VS 2010提供的默认MVC应用程序,让我们想象一下我想要更改“LogonUserControl.ascx”,以便它告诉我已记录的用户(因为它当前正在工作) )或者允许我从那里登录,向我显示用户名和密码的文本框(因此在本例中来自主页)。

所以我接受控制并强烈输入:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Gioby.Models.LogOnModel>" %>
<%
    if (Request.IsAuthenticated) {
%>
        Welcome <b><%: Page.User.Identity.Name  %></b>
        [ <%: Html.ActionLink("Log Off", "LogOff", "Account")%> ]
<%
    }
    else {
%> 
    <% using (Html.BeginForm()) { %>
        <div id="logon">
                <div class="editor-label">
                    <%: Html.LabelFor(m => m.UserName)%>
                    <%: Html.TextBoxFor(m => m.UserName)%>
                    <%: Html.ValidationMessageFor(m => m.UserName, "*") %>
                    <%: Html.LabelFor(m => m.Password)%>
                    <%: Html.PasswordFor(m => m.Password)%>
                    <%: Html.ValidationMessageFor(m => m.Password, "*") %>
                    <input type="submit" value="Log On" />
                </div>

                <div class="editor-label">
                    <%: Html.ActionLink("Register here", "Register", "Account")%> 
                    <%: Html.CheckBoxFor(m => m.RememberMe, new { @class = "pad-left" })%>
                    <%: Html.LabelFor(m => m.RememberMe) %>
                </div>
        </div>
    <% } %>
<%
    }
%>

然后在HomeController上,我添加了一个过程:

 [HttpPost]
 public ActionResult Index(LogOnModel model, string returnUrl)
 {
     if (ModelState.IsValid)
     {
          // ==>> Check Login against your DB

          // Now check if param returnUrl is empty
          if (!String.IsNullOrEmpty(returnUrl))
              return Redirect(returnUrl);

          return RedirectToAction("Index", "Home");
     }

     // If we got this far, something failed, redisplay form
     return View(model);
 }

我在主页上对它进行了测试......它有效!!!

但是当我导航到“注册”视图时(请记住“LogonUserControl.ascx”位于“MasterPage”内部,因此可以从“注册”视图中看到)。

所以当我点击Register按钮时,我收到错误: 传递到字典中的模型项的类型为Site.Models.RegisterModel',但此字典需要Site.Models.LogOnModel'类型的模型项。

问题: 这是否意味着我永远无法将不同的部分组合成一个视图?

假设我想写一个电子商务网站,在主页上我想看到“最常用的标签”,“大多数购买的产品”,“本月产品”,“类别列表”...都在同一个网站内查看,每个人都有自己的HTTP POST操作。

如果可以使用MVC吗?

1 个答案:

答案 0 :(得分:0)

如果我正确理解了问题,那么您有两个使用相同MasterPage的视图,但它们针对不同的ViewModel进行了强类型化。主页面能够包含强类型的部分视图,只要其预期的ViewModel与父视图的ViewModel相同即可。但是,如果您使用的视图具有不同的ViewModel类型,则它不知道该怎么做。

请考虑以下事项:

<% Html.RenderPartial("LogOn") %>

上述代码隐式包含正在呈现的当前视图的模型数据。这跟你说的完全一样:

<% Html.RenderPartial("LogOn", Model) %>

所以这只有在Model是LogOnModel时才有效。请记住,MasterPage实际上是View继承它的一部分,所以即使你把它放在MasterPage中,就好像你在每个继承它的视图中都放了相同的代码。因此,如果View的模型与PartialView的模型不同,则无法使用。一种替代方法是使用继承来确保每个ViewModel都包含母版页所需的所有信息。详细描述了这种方法here

但是这种方法意味着您必须始终使用工厂来生成视图模型,并且每个视图模型都必须知道它将使用哪个母版页。在我们的产品中,我们可以在同一视图上使用不同的母版页,具体取决于用户查看网站的模式,因此将ViewModel与母版页的视图绑定是没有意义的。我们使用RenderAction方法完成您所描述的内容,该方法允许您呈现整个控制器操作,就好像它只是较大视图的一部分一样。讨论了这种方法的一些优点here

现在您可以让您的MasterPage包含您想要的任何小部分视图,但是您将构建每个视图的ViewModel的逻辑分离为负责该特定部分视图的单个控制器操作:

<% Html.RenderAction("LogOnBox") %>

行动:

public ActionResult LogOnBox()
{
    LogOnModel model = GetLogOnModel();
    return PartialView("LogOnUserControl", model);
}

现在,无论您当前的视图使用何种型号,您的母版页都可以包含“最常用的标签”,“大多数购买的产品”,“本月产品”,“类别列表”等。更好的是,这些页面的某些部分可以利用输出缓存,因此如果它们不经常更改,则不必在每次页面加载时重新生成它们。