一个模型可以通过多个编辑器模板传递吗?

Eri*_*ock 6 asp.net-mvc razor

我正在尝试使用编辑器模板显示视图模型,该模板在应用基础对象编辑器模板之前将模型包装在字段集中.

我的看法:

@model Mvc3VanillaApplication.Models.ContactModel

@using (Html.BeginForm())
{
    @Html.EditorForModel("Fieldset")
}
Run Code Online (Sandbox Code Playgroud)

使用fieldset模板(Views/Shared/EditorTemplates/Fieldset.cshtml):

<fieldset>
    <legend>@ViewData.ModelMetadata.DisplayName</legend>
    @Html.EditorForModel()
</fieldset>
Run Code Online (Sandbox Code Playgroud)

而这又为所有对象使用基本模板(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)
}
Run Code Online (Sandbox Code Playgroud)

无论如何,那是我的意图.问题是,当页面使用字段集和图例进行渲染时,不会应用对象模板,因此不会显示任何输入控件.

如果我将视图更改为不指定"Fieldset"模板,则使用Object模板呈现模型的属性,因此不能找到我的Object模板.

是否可以通过多个模板传递相同的模型?

对于它的价值,视图模型如下所示:

namespace Mvc3VanillaApplication.Models
{
    [System.ComponentModel.DisplayName("Contact Info")]
    public class ContactModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

Nic*_*sen 5

我实现了你所拥有的,并且能够重现它.我设置了一个断点,Object.cshtml所以我可以检查它,并且当我使用fieldset模板时,我发现它甚至没有碰到对象模板.然后我逐步完成了fieldset模板,看到它正好调用模板,所以必须在代码中发生一些事情,阻止它显示对象模板.

我打开了MVC3源代码,搜索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 */));
}
Run Code Online (Sandbox Code Playgroud)

显然这不是它,所以我按下F12TemplateHelpers.TemplateHelper,然后再一次在那里我按下F12单线呼叫,它带你到功能的肉.在这里,我发现了从第214行开始的这段代码TemplateHelpers.cs:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

这些评论实际上在代码中,在这里我们有你的问题的答案:一个模型可以通过多个编辑器模板传递吗?,答案是没有*.

话虽这么说,这似乎是一个非常合理的用例,所以寻找替代方案可能是值得的.我怀疑一个模板化的剃刀代表会解决这个包装功能,所以我试了一下.

@{
    Func<dynamic, object> fieldset = @<fieldset><legend>@ViewData.ModelMetadata.DisplayName</legend>@Html.EditorForModel()</fieldset>;
}

@using (Html.BeginForm())
{
    //@Html.EditorForModel("Fieldset")
    //@Html.EditorForModel()
    @fieldset(Model)
}
Run Code Online (Sandbox Code Playgroud)

而且中提琴!有效!我将把它作为扩展(以及更多可重用)方法实现.这是一篇关于模板化剃刀代表的简短博文.


*从技术上讲,你可以重写这个函数并编译你自己的MVC3版本,但它可能比它的价值更麻烦.当我们发现当你定义了几百条路线时,函数很慢,我们试图在职业项目中这样做Html.ActionLink.其余的库存在签名问题,我们认为现在不值得花时间研究并维护未来的MVC版本.