DisplayForModel с ошибкой параметра имени представления

Мой шаблон отображения "PlanAlternate":

@model MyPlan

<div class="span4 compare-column compare-column1">

<div class="compare-row-plan">
    <h3>@Model.Plan.Name</h3>
</div>

@foreach (var benefit in Model.Plan.Benefits)
{
    <div class="compare-row-benefit-description">
        @benefit.Description
    </div>
}

<div class="compare-row-submit">
    <input class="btn" type="submit" value="Apply Now" />
</div>
</div>

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

@model IEnumerable<MyPlan>

<div class="span9 compare-data-wrapper">
   @Html.DisplayForModel("PlanAlternate")
</div>

Это вызывает исключение:

Элемент модели, переданный в словарь, имеет тип «System.Collections.Generic.List`1[MyPlan]», но для этого словаря требуется элемент модели типа «MyPlan».

ОДНАКО, если я переименую шаблон отображения из PlanAlternate.cshtml в MyPlan.cshtml и использую

@Html.DisplayForModel()

Все работает просто отлично. Можете ли вы помочь мне понять, почему это происходит?

Спасибо!

ИЗМЕНИТЬ:

Если я сделаю точно так, как описано выше, где имя файла шаблона отображения совпадает с именем модели представления, но я передам имя представления («MyPlan») в DisplayForModel, он все равно выдаст исключение!! Вызов DisplayForModel без аргументов работает. Мне это кажется очень, очень странным. Почти как ошибка, но я уверен, что это просто то, что я не понимаю.


person Barry    schedule 25.06.2013    source источник
comment
Что это за язык? Можете ли вы добавить еще несколько тегов?   -  person Software Engineer    schedule 25.06.2013


Ответы (2)


Метод DisplayForModel()DisplayFor(m => m)) внутренне использует методы internal static в TemplateHelpers. Код довольно сложен, и я оставлю его на ваше усмотрение, чтобы изучить исходный код более подробно, но подытожу, что происходит:

Когда вы не передаете значение templateName, помощник в основном говорит

Найдите имя представления, которое соответствует названию моей модели, и сгенерируйте HTML-код на основе этого представления для каждого элемента в моей коллекции

Но когда вы передаете значение templateName, помощник в основном говорит

Найти представление, соответствующее templateName, передать ему мою коллекцию и сгенерировать HTML-код на основе этого представления

что приводит к вашему исключению, потому что он передает модель IEnumerable<MyPlan> в представление, которое ожидает модель MyPlan.

Это работает так же, как и при использовании атрибута [TemplateHint], т. е. он передает модель в представление, поэтому, если модель имеет значение IEnumerable<T>, представление также должно быть @model IEnumerable<T>.

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

person Community    schedule 10.03.2016

Ваш шаблон ожидает модель одного экземпляра MyPlan, где ваше представление имеет список объектов MyPlan. Поскольку вы не предоставляете какой-либо объект DisplayForModel, он просто передает модель из представления. Чтобы сделать то, что вы хотите, вам придется обернуть DisplayForModel в цикл for и передать экземпляр MyPlan из IEnumerable на каждой итерации цикла, т.е.

foreach(var myPlan in Model)
{
    @Html.DisplayForModel("PlanAlternate", myPlan)
}

Я не проверял синтаксис, но мне кажется, что это правильно.

person DoctorMick    schedule 25.06.2013
comment
Почему простое переименование шаблона отображения в соответствии с моделью может решить проблему? - person Barry; 25.06.2013
comment
Но почему это работает с @Html.DisplayForModel(), если OP меняет имя файла шаблона отображения, но не @Html.DisplayForModel("PlanAlternate")? - person Martin Dawson; 09.03.2016