Этот вопрос является продолжением для Почему мой DisplayFor не зацикливается на моем IEnumerable <DateTime> ?
Быстрое обновление.
Когда:
- модель имеет свойство типа
IEnumerable<T>
- вы передаете это свойство в
Html.EditorFor()
, используя перегрузку, которая принимает только выражение лямбда - У вас есть шаблон редактора для типа
T
в разделе Views/Shared/EditorTemplates
тогда механизм MVC автоматически вызовет шаблон редактора для каждого элемента в перечислимой последовательности, создав список результатов.
Например, когда существует класс модели Order
со свойством Lines
:
public class Order
{
public IEnumerable<OrderLine> Lines { get; set; }
}
public class OrderLine
{
public string Prop1 { get; set; }
public int Prop2 { get; set; }
}
И есть представление Views/Shared/EditorTemplates/OrderLine.cshtml:
@model TestEditorFor.Models.OrderLine
@Html.EditorFor(m => m.Prop1)
@Html.EditorFor(m => m.Prop2)
Затем, когда вы вызываете @Html.EditorFor(m => m.Lines)
из представления верхнего уровня, вы получите страницу с текстовыми полями для каждой строки заказа, а не только.
Однако, как вы можете видеть в связанном вопросе, это работает только при использовании этой конкретной перегрузки EditorFor
. Если вы укажете имя шаблона (чтобы использовать шаблон, не названный в честь класса OrderLine
), тогда автоматическая обработка последовательности не произойдет, и вместо этого произойдет ошибка времени выполнения.
В этот момент вам нужно будет объявить свою собственную модель шаблона как IEnumebrable<OrderLine>
и вручную перебрать ее элементы так или иначе, чтобы вывести все из них, например.
@foreach (var line in Model.Lines) {
@Html.EditorFor(m => line)
}
И вот где начинаются проблемы.
Элементы управления HTML, сгенерированные таким образом, имеют одинаковые идентификаторы и имена. Когда вы позже добавите POST, связующее устройство модели не сможет построить массив OrderLine
s, а объект модели, который вы получите в методе HttpPost в контроллере, будет null
.
Это имеет смысл, если вы посмотрите на выражение лямбда - это действительно не связывает объект, который строится с местом в модели, из которой он приходит.
Я пробовал различные способы итерации по элементам, и, казалось бы, единственный способ - переопределить модель шаблона как IList<T>
и перечислить его с помощью for
:
@model IList<OrderLine>
@for (int i = 0; i < Model.Count(); i++)
{
@Html.EditorFor(m => m[i].Prop1)
@Html.EditorFor(m => m[i].Prop2)
}
Затем в представлении верхнего уровня:
@model TestEditorFor.Models.Order
@using (Html.BeginForm()) {
@Html.EditorFor(m => m.Lines, "CustomTemplateName")
}
который дает правильно названные элементы управления HTML, которые должным образом распознаются связующим устройством модели в submit.
Пока это работает, это кажется очень неправильным.
Каков правильный, идиоматический способ использования настраиваемого шаблона редактора с EditorFor
, сохраняя при этом все логические ссылки, которые позволяют движку генерировать HTML, подходящий для привязки модели?