【问题标题】:ASP.NET MVC editor template for property属性的 ASP.NET MVC 编辑器模板
【发布时间】:2012-08-30 07:48:11
【问题描述】:

通常我通过@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 显示空字符串)中。我做错了什么?

【问题讨论】:

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


    【解决方案1】:

    您正在从您的编辑器调用编辑器。正如@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")

    并且,关于 无论显示名称如何都会呈现标签,为了防止标签在没有显示名称的情况下呈现,请将您的 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 等),并且只有当您有一些不是字符串的“未知”属性并且没有特定的编辑器时(即字节 [])它会为它调用 object.ascx,但这是 NOT 为当前属性调用编辑器(您正在尝试做的事情):

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


    摘要

    短版:

    相同属性的更多编辑器基本上是功能差异的解决方案(“是/否,我想要这里的无线电组和那里的下拉菜单)”,对于视觉差异,应该使用部分视图,因为您可以尽可能多地嵌套它们如您所愿,因为您明确地按名称调用它们,因此没有施加任何限制,您有责任防止任何潜在的递归。

    长版:

    我一直在调查这个问题,因为我有同样的问题,我正在使用编辑器模板来渲染 &lt;li&gt;&lt;td&gt; 元素(取决于配置/主题)并从它内部调用另一个包含标签和输入(两种情况相同,但如果属性为 bool,则输入在标签之前),我再次调用第三个模板进行输入(以防止标签/输入和输入/标签场景的代码重复),但这不起作用.虽然我没有在 msdn 或其他相关来源上找到解释,但我发现编辑器什么都不提供的唯一情况是当您想要为当前编辑器的上下文的属性呈现编辑器时(所以它实际上正是我已经引用:“在给定的 Views 特定上下文中,您只能在运行时为给定类型使用 1 个模板。”)。在对此进行了更多思考之后,我现在相信他们施加此限制是正确的,因为属性 x 只能使用一个编辑器呈现。您可以根据需要为属性 x 拥有任意数量的编辑器,但您不能使用多个模板渲染一个属性一次。您用于渲染属性 x 的任何模板都可以使用其他模板来渲染属性 x 的部分,但您不能多次对 x 使用(相同或不同)编辑器(相同的逻辑适用于拥有两个或多个属性 x(相同类型)和名称)在同一型号上)。

    此外,如果您可以将当前属性的另一个模板插入到当前模板中,则可以为当前属性链接任意数量的模板,并且很容易导致递归,所以它会以一种或另一种方式引导您 stackoverflow :)

    【讨论】:

    • 是的,我是从编辑器中调用编辑器,但是当您使用带有默认对象编辑器模板的 RenderModel 时发生的情况是一样的。它适用于对象编辑器模板。那么我的代码和它有什么不同呢?
    • 您指的是来自bradwilson.typepad.com/blog/2009/10/… 的默认模板吗?有一个区别,prop.PropertyName 用于调用复杂模型属性的编辑器,对于模型本身使用 。请记住,对于所有属性,它们的默认编辑器将被调用,因此字符串属性等的字符串,因此如果没有“特定”编辑器,它将调用带有显示文本的对象,因为无法编辑该“未知”对象。
    • 你是对的,问题是我这里有一种递归。但我实际上看不出 ASP.NET MVC 无法解决它的任何原因。
    • 好吧,我要问的第一个问题是,它应该在这里调用哪个模板?我有同样的问题,我有将标签/输入放入 li 或 td 元素的编辑器(取决于我想要列表还是表格),并且两者都呈现@Html.LabelFor,但我想要在两者中使用相同的编辑器(@Html.EditorFor (m=>m, "Editor") 和同样的问题,不能从两个模板调用一个编辑器,所以我最终将 Editor.cshtml(剃刀扩展)移动了一级,进入 Views/Shared 文件夹并使用@Html.Partial ("Editor") 而不是我的编辑器模板中的@Html.Editor(propertyName) 和我的显示模板中的@Html.Partial("Display")。
    • 如果我没有明确指定模板名称,我希望它首先调用它会调用的编辑器
    【解决方案2】:

    “x.SomeProperty”是什么类型?我现在假设它的类型称为 Property。

    MyModel.cs

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

    属性.cs

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

    Views/Shared/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 助手提供模板名称,它会找到 名称匹配的编辑器模板 SomeProperty的类型

    更新:

    要为字符串制作自定义编辑器模板:

    型号

    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) 
    

    Views/Shared/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)
    

    【讨论】:

    • SomeProperty 的类型是字符串,所以我希望文本框被渲染
    • 我不需要字符串模板,我需要任何属性的通用模板
    • 好吧,我明白了。不确定这是否可能。您可以使用 @model 对象更改“@model 字符串”部分并将 Html.Editor 替换为 Html.TextBox 并且它会起作用。不过,它始终是一个文本框。老实说,我没有看到为通用对象创建编辑器模板的意义。另一种解决方法是使用部分视图而不是编辑器模板。
    猜你喜欢
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 2023-03-13
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多