Подтвердить что ты не робот

Шаблон редактора ASP.NET MVC для свойства

Обычно я обрабатываю свои формы с помощью @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 показывает пустую строку). Что я делаю неправильно?

4b9b3361

Ответ 1

Вы вызываете редактор из своего редактора. Как @RPM1984 перефразирует @darin-dmitrov в комментарии this: У вас может быть только один шаблон, используемый во время выполнения для данного типа, в определенном представлении контекст.

Если вы измените свой вид на рендеринг текстового поля вместо редактора, он работает, я просто попытался:

<%@ 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) (я уже поместил его таким образом в основной блок кода)

ИЗМЕНИТЬ Это редактирование относится к вопросу, связанному с шаблоном редактора объектов default.ascx. Это код объекта .ascx, взятый из Блог Брэда Уилсона:

<%@ 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 и т.д.), И только если у вас есть какое-то "неизвестное" свойство, которое не является строкой, и для него нет специального редактора (т.е. Byte []) он будет ссылаться на объект .ascx для него, но это НЕ редактор вызовов для текущего свойства (что вы пытаетесь сделать):

Основной задачей шаблонов объектов является отображение всех свойств сложного объекта вместе с метками для каждого свойства. Тем не менее, он также несет ответственность за отображение значения моделей NullDisplayText, если его значение равно null, а также за то, что оно обеспечивает только один уровень свойств (также известный как "мелкое погружение" объекта). В следующем блоге хорошо расскажите о способах настройки этого шаблона, включая выполнение операций "глубокого погружения".


СУЩНОСТЬ

Краткая версия:

Больше редакторов для такого же свойства в основном является решением для функциональных различий ( "для да/нет, я хочу здесь группу радио и там выпадающего списка" ), а для визуальных различий следует использовать частичные представления, так как вы можете их вложить как вы хотите, потому что вы явно называете их по имени, так что ограничений нет, вы несете ответственность за предотвращение любых потенциальных рекурсий.

Длинная версия:

Я изучаю это, так как у меня такая же проблема, я использую редакторский шаблон для рендеринга <li> или <td> element (в зависимости от конфигурации/темы), и изнутри он вызывает другой редактор, который содержит метки и input (то же самое для обоих случаев, но если свойство имеет значение bool, то ввод перед меткой), где я снова вызываю третий шаблон для ввода (чтобы предотвратить дублирование кода для сценариев ярлыков/ввода и ввода/метки), но это не работает, Хотя я не нашел объяснений в msdn или другом соответствующем источнике, я понял, что единственный сценарий, когда редактор ничего не дает, - это когда вы хотите визуализировать редактор для свойства, являющегося контекстом текущего редактора (так что на самом деле именно то, что я уже цитируется: "У вас может быть только один шаблон, используемый во время выполнения для данного типа, в конкретном конкретном контексте Views".). Подумав еще об этом, теперь я верю, что они правы, вводя этот предел, поскольку свойство x может быть представлено только одним редактором. У вас может быть столько редакторов для свойства x, сколько хотите, но вы не можете отобразить одно свойство после использования нескольких шаблонов. Любой из ваших шаблонов для рендеринга свойства x может использовать другие шаблоны для рендеринга PARTS свойства x, но вы не можете использовать (тот же или другой) редактор для x более одного раза (та же самая логика относится к наличию двух или более свойств x (одного типа) и имя) на той же модели).

Кроме того, если вы можете вставить другой шаблон для текущего свойства в текущий шаблон, который позволяет связать любое количество шаблонов для текущего свойства и может легко вызвать рекурсию, так что так или иначе это приведет вас к stackoverflow:)

Ответ 2

Какой тип "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; }
}

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)

Если вы не предоставляете templatename для помощника EditorFor, он находит editortemplate, имя которого соответствует типу SomeProperty.

Update:

Чтобы создать пользовательский шаблон editortemplate для строки:

Model

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)