简体   繁体   English

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

[英]ASP.NET MVC editor template for property

Usually I render my forms by @Html.RenderModel, but this time I have a complex rendering logic and I render it manually. 通常我通过@ Html.RenderModel渲染我的表单,但这次我有一个复杂的渲染逻辑,我手动渲染它。 I decided to create a editor template for one property. 我决定为一个属性创建一个编辑器模板。 Here is the code (copy pasted from default object editor template implementation): 这是代码(从默认对象编辑器模板实现粘贴的副本):

<%@ 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>
<% } %>

And here is how I use it: 以下是我如何使用它:

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

But it didn't work: labels are rendered regardless of DisplayName and editors are not rendered at all (in Watches Html.Editor(modelMetadata.PropertyName shows empty string). What am I doing wrong? 但它不起作用:无论DisplayName如何都会呈现标签,并且根本不呈现编辑器(在Watches Html.Editor中(modelMetadata.PropertyName显示空字符串)。我做错了什么?

You are calling editor from your editor. 您正在从编辑器中调用编辑器。 As @RPM1984 rephrases @darin-dmitrov in comment in this answer: You can only have 1 template used at runtime for a given type, in a given Views particular context . 正如@ RPM1984在这个答案中评论@ darin-dmitrov: 在给定的Views特定上下文中,您只能在给定类型的运行时使用1个模板

If you change your view to render textbox instead of editor, it works, I just tried: 如果您将视图更改为渲染文本框而不是编辑器,它可以工作,我只是尝试:

<%@ 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>
<% } %>

If you want to render something else instead of textbox (ie dropdown list), you need to decide that inside your template for that property and render it. 如果要渲染其他内容而不是文本框(即下拉列表),则需要在模板内部确定该属性并进行渲染。 Or, if you have something common for more editors, I usually extract that into partial view in Shared folder, and just use Html.Partial("ViewName") 或者,如果您有更多编辑器的共同点,我通常会将其提取到Shared文件夹中的部分视图中,并使用Html.Partial("ViewName")

And, regarding labels are rendered regardless of DisplayName , to prevent label from rendering if there is no display name, change your if condition to !String.IsNullOrEmpty(modelMetadata.DisplayName) (I already put it that way in main code block) 并且, 无论DisplayName如何呈现标签 ,以防止在没有显示名称的情况下呈现标签,将if条件更改为!String.IsNullOrEmpty(modelMetadata.DisplayName) (我已经将它放在主代码块中)

EDIT This edit refers to question related to object.ascx default editor template. 编辑此编辑是指与object.ascx默认编辑器模板相关的问题。 This is code of object.ascx, taken from Brad Wilson's blog : 这是object.ascx的代码,取自Brad Wilson的博客

<%@ 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>
        <% } %>
    <% } %>
<% } %>

This code indeed calls Html.Editor from inside of editor, but inside a loop which creates list of editors for properties of complex model. 这段代码确实从编辑器内部调用了Html.Editor,但是在一个循环中,它为复杂模型的属性创建了编辑器列表。 Each of these calls will invoke corresponding editor (ie for string it will show string.ascx there etc), and only if you have some "unknown" property which is not string and there is no specific editor for it (ie byte[]) it will invoke object.ascx for it, but this is NOT calling editor for the current property (what you are trying to do): 这些调用中的每一个都将调用相应的编辑器(即对于字符串,它将显示string.ascx等),并且只有当你有一些不是字符串的“unknown”属性并且没有特定的编辑器时(即byte [])它会为它调用object.ascx,但这不是调用当前属性的编辑器(你要做的是):

The Object template's primary responsibility is displaying all the properties of a complex object, along with labels for each property. 对象模板的主要职责是显示复杂对象的所有属性,以及每个属性的标签。 However, it's also responsible for showing the value of the model's NullDisplayText if it's null, and it's also responsible for ensuring that you only show one level of properties (also known as a “shallow dive” of an object). 但是,它还负责显示模型的NullDisplayText的值(如果它为null),并且它还负责确保您只显示一个级别的属性(也称为对象的“浅层”)。 In the next blog post, we'll talk about ways to customize this template, including performing “deep dive” operations. 在下一篇博客文章中,我们将讨论自定义此模板的方法,包括执行“深度潜水”操作。


SUMMARY 摘要

Short version: 精简版:

More editors for same property is basically solution for functional differences ("for yes/no I want here radio group and there drop-down)", and for visual differences partial views should be used, as you can nest them as much as you want, because you explicitly call them by name so there is no limits imposed, you are responsible to prevent any potential recursions. 相同属性的更多编辑器基本上是功能差异的解决方案(“是/否我想在这里收音机组和下拉列表”),并且对于视觉差异应该使用部分视图,因为您可以根据需要嵌套它们,因为你明确地通过名称调用它们所以没有限制,你有责任防止任何潜在的递归。

Long version: 长版:

I have been investigating this, as I have the same problem, I'm using editor template to render <li> or <td> element (depending on config/theme) and from inside it call another editor which contains label and input (same for both cases, but if property is bool then input is before label), where I'm again calling third template for input (to prevent duplicating code for label/input and input/label scenarios), but this does not work. 我一直在研究这个,因为我有同样的问题,我正在使用编辑器模板来渲染<li><td>元素(取决于配置/主题),并从内部调用另一个包含标签和输入的编辑器(相同)对于这两种情况,但如果属性是bool然后输入在标签之前),我再次调用第三个输入模板(以防止复制标签/输入和输入/标签方案的代码),但这不起作用。 Although I did not found explanation on msdn or other relevant source, I figured out that the only scenario when editor gives nothing is when you want to render editor for the property which is the context of current editor (so it is actually exactly what I already quoted: "You can only have 1 template used at runtime for a given type, in a given Views particular context."). 虽然我没有在msdn或其他相关来源上找到解释,但我发现编辑器什么都没有给出的唯一情况就是当你想为属性渲染编辑器时,这是当前编辑器的上下文(所以它实际上就是我已经是引用:“在给定的Views特定上下文中,您只能在给定类型的运行时使用1个模板。”)。 After thinking some more about this, I believe now that they are right in imposing this limit, as property x can only be rendered using one editor. 在考虑了更多这方面之后,我相信他们现在正确实施这个限制,因为属性x只能使用一个编辑器来呈现。 You can have as many editors for property x as you want, but you cannot render one property once using more than one template. 您可以根据需要为属性x创建尽可能多的编辑器,但是使用多个模板无法渲染一个属性。 Any of your templates for rendering property x can use other templates to render PARTS of property x, but you cannot use (same or different) editor for x more than once (the same logic applies as to having two or more properties x (same type and name) on same model). 用于渲染属性x的任何模板都可以使用其他模板来渲染属性x的PARTS,但是您不能多次使用(相同或不同)x的编辑器(相同的逻辑适用于具有两个或更多属性x(相同类型)和名称)在同一型号上)。

Besides, if you could insert another template for current property into current template, that enables chaining any number of templates for current property, and can easily cause recursion, so one way or another it will lead you to stackoverflow :) 此外,如果你可以将当前属性的另一个模板插入到当前模板中,那么可以为当前属性链接任意数量的模板,并且很容易导致递归,所以这样或那样会引导你进行stackoverflow :)

What type is the "x.SomeProperty"? 什么类型的“x.SomeProperty”? I'm gonna assume for now it's type is called Property. 我现在要假设它的类型叫做Property。

MyModel.cs MyModel.cs

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

Property.cs Property.cs

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

Views/Shared/EditorTemplates/Property.cshtml 查看/共享/ EditorTemplates / Property.cshtml

@model MvcApplication1.Models.Property

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

MyView.cshtml MyView.cshtml

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

If you don't provide templatename for EditorFor helper it finds editortemplate which name matches SomeProperty's type . 如果你没有为EditorFor helper提供templatename,它会找到editortemplate哪个名称与 SomeProperty的类型 匹配

Update: 更新:

To make a custom editortemplate for string you do: 要为字符串进行自定义editortemplate,您可以:

Model 模型

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

View: 视图:

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

Or alternatively: 或者:

Model: 模型:

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

View: 视图:

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

Views/Shared/EditorTemplates/Property.cshtml: 查看/共享/ 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM