用于属性的ASP.NET MVC编辑器模板

时间:2012-08-30 07:48:12

标签: .net asp.net-mvc mvc-editor-templates

通常我会通过@ Html.RenderModel渲染我的表单,但这次我有一个复杂的渲染逻辑,我手动渲染它。我决定为一个属性创建一个编辑器模板。这是代码(从默认对象编辑器模板实现粘贴的副本):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% var modelMetadata = ViewData.ModelMetadata; %>
<% if (modelMetadata.HideSurroundingHtml) { %>
    <%= Html.Editor(modelMetadata.PropertyName) %>
<% } else { %>
    <% if (!String.IsNullOrEmpty(Html.Label(modelMetadata.PropertyName).ToHtmlString())) { %>
        <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div>
    <% } %>
    <div class="editor-field">
        <%= Html.Editor(modelMetadata.PropertyName) %>
        <%= Html.ValidationMessage(modelMetadata.PropertyName) %>
    </div>
<% } %>

以下是我如何使用它:

@Html.EditorFor(x => x.SomeProperty, "Property") //"Property" is template above

但它不起作用:无论DisplayName如何都会呈现标签,并且根本不呈现编辑器(在Watches Html.Editor中(modelMetadata.PropertyName显示空字符串)。我做错了什么?

2 个答案:

答案 0 :(得分:12)

您正在编辑中调用编辑器。正如@ {{{{{{{{{{{{{{{{{{{{{<}} > @ RPM1984在this的评论中重新评论@ darin-dmitrov:在给定的视图特定上下文中,您只能在给定类型的运行时使用1个模板

如果您将视图更改为渲染文本框而不是编辑器,那么它可以工作,我只是尝试了:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% var modelMetadata = ViewData.ModelMetadata; %>
<% if (modelMetadata.HideSurroundingHtml)
   { %>
   <%= Html.Editor(modelMetadata.PropertyName) %>
<% }
   else
   { %>
   <% if (!String.IsNullOrEmpty(modelMetadata.DisplayName))
       { %>
       <div class="editor-label"><%= Html.Label(modelMetadata.PropertyName) %></div>
    <% } %>
    <div class="editor-field"><%= Html.TextBox(modelMetadata.PropertyName) %> <%= Html.ValidationMessage(modelMetadata.PropertyName) %></div>
<% } %>

如果要渲染其他内容而不是文本框(即下拉列表),则需要在模板中确定该属性并进行渲染。或者,如果您有更多编辑器的共同点,我通常会将其提取到共享文件夹中的部分视图中,并使用Html.Partial("ViewName")

并且,无论DisplayName 如何呈现标签,为了防止在没有显示名称的情况下呈现标签,请将if条件更改为!String.IsNullOrEmpty(modelMetadata.DisplayName)(我已将其置于主要代码块)

修改 此编辑引用与object.ascx默认编辑器模板相关的问题。 这是object.ascx的代码,取自Brad Wilson's blog

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
    <%= ViewData.ModelMetadata.SimpleDisplayText%>
<% }
   else { %>    
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit
                         && !ViewData.TemplateInfo.Visited(pm))) { %>
        <% if (prop.HideSurroundingHtml) { %>
            <%= Html.Editor(prop.PropertyName) %>
        <% }
           else { %>
            <% if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())) { %>
                <div class="editor-label"><%= Html.Label(prop.PropertyName) %></div>
            <% } %>
            <div class="editor-field">
                <%= Html.Editor(prop.PropertyName) %>
                <%= Html.ValidationMessage(prop.PropertyName, "*") %>
            </div>
        <% } %>
    <% } %>
<% } %>

这段代码确实从编辑器内部调用了Html.Editor,但是在一个循环中,它为复杂模型的属性创建了编辑器列表。这些调用中的每一个都将调用相应的编辑器(即对于字符串,它将显示string.ascx等),并且只有当你有一些不是字符串的“unknown”属性并且没有特定的编辑器时(即byte [])它会为它调用object.ascx,但这是 NOT 当前属性的调用编辑器(你要做的是):

对象模板的主要职责是显示复杂对象的所有属性,以及每个属性的标签。但是,它还负责显示模型的NullDisplayText的值(如果它为null),并且它还负责确保您只显示一个级别的属性(也称为对象的“浅层”)。在下一篇博客文章中,我们将讨论自定义此模板的方法,包括执行“深度潜水”操作。


<强>概要

简短版本:

同一属性的更多编辑器基本上是功能差异的解决方案(“是/否我想在这里收音机组和下拉列表”),并且对于视觉差异应该使用局部视图,因为你可以将它们嵌套如你所愿,因为你明确地按名称调用它们所以没有限制,你有责任防止任何潜在的递归。

长版:

我一直在研究这个,因为我有同样的问题,我正在使用编辑器模板来渲染<li><td>元素(取决于配置/主题),并从内部调用另一个编辑器其中包含标签和输入(两种情况都相同,但如果属性是bool,则输入在标签之前),我再次调用第三个输入模板(以防止复制标签/输入和输入/标签方案的代码),但是这不起作用。虽然我没有在msdn或其他相关来源上找到解释,但我发现编辑器什么都没有给出的唯一情况就是当你想为属性渲染编辑器时,这是当前编辑器的上下文(所以它实际上就是我已经是引用:“在给定的Views特定上下文中,您只能在给定类型的运行时使用1个模板。”)。在考虑了更多这方面之后,我相信他们现在正确实施这个限制,因为属性x只能使用一个编辑器来呈现。您可以根据需要为属性x创建尽可能多的编辑器,但是使用多个模板无法渲染一个属性。用于渲染属性x的任何模板都可以使用其他模板来渲染属性x的PARTS,但是您不能多次使用(相同或不同)x的编辑器(相同的逻辑适用于具有两个或更多属性x(相同类型)和名称)在同一型号上。)

此外,如果您可以将当前属性的另一个模板插入当前模板,则可以为当前属性链接任意数量的模板,并且很容易导致递归,因此会以某种方式引导您进入 stackoverflow < / em>:)

答案 1 :(得分:0)

什么类型的“x.SomeProperty”?我现在要假设它的类型叫做Property。

MyModel.cs

public class MyModel
{
    public Property SomeProperty { get; set; }
}

Property.cs

public class Property
{
    [Display(Name="Foo")]
    public int Value { get; set; }
}

查看/共享/ EditorTemplates / Property.cshtml

@model MvcApplication1.Models.Property

@Html.LabelFor(model => model.Value)
@Html.EditorFor(model => model.Value)
@Html.ValidationMessageFor(model => model.Value)

MyView.cshtml

@Html.EditorFor(model=>model.SomeProperty)

如果你没有为EditorFor helper提供templatename,它会找到editortemplate 名称匹配 SomeProperty的类型

<强>更新

要为字符串创建自定义editortemplate,请执行以下操作:

模型

public class MyModel
{
    public string SomeProperty { get; set; }
}

查看:

@Html.EditorFor(model => model.SomeProperty,"Property")

或者:

型号:

public class MyModel
{
    [DataType("Property")]
    public string SomeProperty { get; set; }
}

查看:

@Html.EditorFor(model => model.SomeProperty) 

查看/共享/ EditorTemplates / Property.cshtml:

@model string

@Html.Raw("I'm using property editortemplate:")
@Html.Label(ViewData.ModelMetadata.PropertyName)
@Html.Editor(ViewData.ModelMetadata.PropertyName)
@Html.ValidationMessage(ViewData.ModelMetadata.PropertyName)