Forma correcta e idiomática de usar plantillas de editor personalizadas con modelos IEnumerable en ASP.NET MVC

Esta pregunta es un seguimiento de¿Por qué mi DisplayFor no recorre mi IEnumerable <DateTime>?

Una actualización rápida

Cuando:

el modelo tiene una propiedad de tipoIEnumerable<T>pasas esta propiedad aHtml.EditorFor() usando la sobrecarga que solo acepta la expresión lambdatienes una plantilla de editor para el tipoT en Vistas / Compartido / Plantillas de editor

entonces el motor MVC invocará automáticamente la plantilla del editor para cada elemento en la secuencia enumerable, produciendo una lista de los resultados.

Por ejemplo, cuando hay una clase de modeloOrder con propiedadLines:

public class Order
{
    public IEnumerable<OrderLine> Lines { get; set; }
}

public class OrderLine
{
    public string Prop1 { get; set; }
    public int Prop2 { get; set; }
}

Y hay una vista Views / Shared / EditorTemplates / OrderLine.cshtml:

@model TestEditorFor.Models.OrderLine

@Html.EditorFor(m => m.Prop1)
@Html.EditorFor(m => m.Prop2)

Entonces, cuando invocas@Html.EditorFor(m => m.Lines) desde la vista de nivel superior, obtendrá una página con cuadros de texto para cada línea de pedido, no solo una.

Sin embargo, como puede ver en la pregunta vinculada, esto solo funciona cuando usa esa sobrecarga particular deEditorFor. Si proporciona un nombre de plantilla (para usar una plantilla que no tenga nombre después deOrderLine clase), entonces el manejo automático de la secuencia no ocurrirá, y en su lugar ocurrirá un error de tiempo de ejecución.

En ese momento, deberá declarar el modelo de su plantilla personalizada comoIEnumebrable<OrderLine> e iterar manualmente sobre sus elementos de una forma u otra para generarlos todos, p.

@foreach (var line in Model.Lines) {
    @Html.EditorFor(m => line)
}

Y ahí es donde comienzan los problemas.

Los controles HTML generados de esta manera tienen todos los mismos identificadores y nombres. Cuando más tarde los publique, el modelo de carpeta no podrá construir una matriz deOrderLines, y el objeto modelo que obtienes en el método HttpPost en el controlador seránull.
Esto tiene sentido si observa la expresión lambda: en realidad no vincula el objeto que se está construyendo con un lugar en el modelo del que proviene.

He intentado varias formas de iterar sobre los elementos, y parece que la única forma es volver a declarar el modelo de la plantilla comoIList<T> y enumerarlo confor:

@model IList<OrderLine>

@for (int i = 0; i < Model.Count(); i++)
{ 
    @Html.EditorFor(m => m[i].Prop1)
    @Html.EditorFor(m => m[i].Prop2)
}

Luego, en la vista de nivel superior:

@model TestEditorFor.Models.Order

@using (Html.BeginForm()) {
    @Html.EditorFor(m => m.Lines, "CustomTemplateName")
}

que proporciona controles HTML correctamente nombrados que el archivador de modelos reconoce correctamente en un envío.

Si bien esto funciona, se siente muy mal.

¿Cuál es la forma correcta e idiomática de usar una plantilla de editor personalizada conEditorFor, al tiempo que conserva todos los enlaces lógicos que permiten que el motor genere HTML adecuado para el modelo de carpeta?

Respuestas a la pregunta(4)

Su respuesta a la pregunta