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