我正在尝试使用编辑器模板显示视图模型,该模板在应用基础对象编辑器模板之前将模型包装在字段集中。
我的观点:
@model Mvc3VanillaApplication.Models.ContactModel
@using (Html.BeginForm())
{
@Html.EditorForModel("Fieldset")
}
使用字段集模板(Views / Shared / EditorTemplates / Fieldset.cshtml):
<fieldset>
<legend>@ViewData.ModelMetadata.DisplayName</legend>
@Html.EditorForModel()
</fieldset>
反过来,它为所有对象使用基本模板(Views / Shared / EditorTemplates / Object.cshtml):
@foreach (var prop in ViewData.ModelMetadata.Properties.Where(x =>
x.ShowForEdit && !x.IsComplexType && !ViewData.TemplateInfo.Visited(x)))
{
@Html.Label(prop.PropertyName, prop.DisplayName)
@Html.Editor(prop.PropertyName)
}
无论如何,这是我的意图。问题是,当页面呈现字段集和图例时,不应用对象模板,因此不显示输入控件。
如果我将视图更改为不指定“Fieldset”模板,则使用Object模板呈现模型的属性,因此不能找到我的Object模板。
是否可以通过多个模板传递相同的模型?
对于它的价值,视图模型如下所示:
namespace Mvc3VanillaApplication.Models
{
[System.ComponentModel.DisplayName("Contact Info")]
public class ContactModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
答案 0 :(得分:5)
我实施了你所拥有的,并且能够重现它。我在Object.cshtml
中设置了一个断点,所以我可以检查它,并且当我使用fieldset模板时,我发现它甚至没有碰到对象模板。然后我逐步完成了fieldset模板,看到它正好调用模板,所以必须在代码中发生一些事情,阻止它显示对象模板。
我打开了MVC3 source code,搜索了EditorForModel
并找到了正确的功能。
public static MvcHtmlString EditorForModel(this HtmlHelper html) {
return MvcHtmlString.Create(TemplateHelpers.TemplateHelper(html, html.ViewData.ModelMetadata, String.Empty, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
}
显然不是这样,所以我在F12
上按了TemplateHelpers.TemplateHelper
,再次在那里我按F12
进行单行调用,这会将你带到函数的内容。在这里,我从TemplateHelpers.cs
的第214行开始发现这段短代码:
// Normally this shouldn't happen, unless someone writes their own custom Object templates which
// don't check to make sure that the object hasn't already been displayed
object visitedObjectsKey = metadata.Model ?? metadata.RealModelType;
if (html.ViewDataContainer.ViewData.TemplateInfo.VisitedObjects.Contains(visitedObjectsKey)) { // DDB #224750
return String.Empty;
}
这些评论实际上在代码中,我们在这里得到了您的问题的答案:一个模型可以通过多个编辑器模板传递吗?,答案是否* 。
话虽这么说,这似乎是一个非常合理的用例,所以找到一个替代方案可能是值得的。我怀疑一个模板化的剃刀委托会解决这个包装功能,所以我试了一下。
@{
Func<dynamic, object> fieldset = @<fieldset><legend>@ViewData.ModelMetadata.DisplayName</legend>@Html.EditorForModel()</fieldset>;
}
@using (Html.BeginForm())
{
//@Html.EditorForModel("Fieldset")
//@Html.EditorForModel()
@fieldset(Model)
}
中提琴!有效!我将把它作为扩展(以及更多可重用)方法实现。这是一篇关于templated razor delegates的简短博文。
*从技术上讲,你可以重写这个函数并编译你自己的MVC3版本,但它可能比它的价值更麻烦。当我们发现Html.ActionLink
函数在定义了几百条路径时速度很慢时,我们尝试在careers项目上执行此操作。其余的库存在签名问题,我们认为现在不值得花时间研究并维护MVC的未来版本。
答案 1 :(得分:2)
在第一个cshtml模板中,我们可以重新创建ViewData.TemplateInfo(并清除VisitedObjects列表)
var templateInfo = ViewData.TemplateInfo;
ViewData.TemplateInfo = new TemplateInfo
{
HtmlFieldPrefix = templateInfo.HtmlFieldPrefix,
FormattedModelValue = templateInfo.FormattedModelValue
};
现在我们可以调用具有相同模型的另一个模板
@Html.DisplayForModel("SecondTemplate")