Можно ли пропустить одну модель через несколько шаблонов редактора? - PullRequest
6 голосов
/ 31 мая 2011

Я пытаюсь отобразить модель представления, используя шаблон редактора, который оборачивает модель в набор полей перед применением базового шаблона редактора объектов.

Мое представление:

@model Mvc3VanillaApplication.Models.ContactModel

@using (Html.BeginForm())
{
    @Html.EditorForModel("Fieldset")
}

Использует шаблон набора полей (Views / Shared / EditorTemplates / Fieldset.cshtml):

<fieldset>
    <legend>@ViewData.ModelMetadata.DisplayName</legend>
    @Html.EditorForModel()
</fieldset>

, который, в свою очередь, использует базовый шаблон для всех объектов (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)
}

В любом случае, это мое намерение.Проблема в том, что, хотя страница отображается с набором полей и легендой, шаблон объекта не применяется, поэтому элементы управления вводом не отображаются.

Если я изменю представление, чтобы не указывать шаблон "Fieldset", тогда мойсвойства модели отображаются с использованием шаблона объекта, поэтому мой шаблон объекта не может быть найден.

Можно ли пропустить одну и ту же модель через несколько шаблонов?

Для чего это стоитМодель вида выглядит так:

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

Ответы [ 2 ]

5 голосов
/ 02 июня 2011

Я реализовал то, что у вас есть, и смог воспроизвести это. Я установил точку останова в 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 */));
}

Очевидно, что это не так, поэтому я нажал F12 на TemplateHelpers.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;
}

Эти комментарии на самом деле находятся в коде, и здесь у нас есть ответ на ваш вопрос: Можно ли пропустить одну модель через несколько шаблонов редактора? , ответ нет *.

При этом, похоже, это очень разумный вариант использования такой функции, поэтому поиск альтернативы, вероятно, стоит усилий. Я подозревал, что шаблонный делегат решит эту упаковочную функцию, поэтому я попробовал.

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

@using (Html.BeginForm())
{
    //@Html.EditorForModel("Fieldset")
    //@Html.EditorForModel()
    @fieldset(Model)
}

И альт! Это сработало! Я оставлю это на ваше усмотрение, чтобы реализовать это как расширение (и гораздо более многократно используемый) метод. Вот короткое сообщение в блоге о шаблонных делегатах бритвы .


* Технически вы можете переписать эту функцию и скомпилировать свою собственную версию MVC3, но это, вероятно, больше проблем, чем стоит. Мы попытались сделать это в проекте careers , когда обнаружили, что функция Html.ActionLink работает довольно медленно, если у вас определено несколько сотен маршрутов. Существует проблема подписи с остальными библиотеками, которые, как мы решили, не стоили нашего времени, чтобы проработать сейчас и поддерживать будущие выпуски MVC.

2 голосов
/ 19 апреля 2016

В первом шаблоне cshtml мы можем воссоздать ViewData.TemplateInfo (и очистить список VisitedObjects)

var templateInfo = ViewData.TemplateInfo;
ViewData.TemplateInfo = new TemplateInfo
{
    HtmlFieldPrefix = templateInfo.HtmlFieldPrefix,
    FormattedModelValue = templateInfo.FormattedModelValue
};

теперь мы можем вызвать другой шаблон с той же моделью

@Html.DisplayForModel("SecondTemplate")
...