Richtige, idiomatische Methode zur Verwendung benutzerdefinierter Editorvorlagen mit IEnumerable-Modellen in ASP.NET MVC

Diese Frage ist ein Follow-up fürWarum durchläuft mein DisplayFor nicht meinen IEnumerable <DateTime>?

Eine schnelle Erfrischung.

Wann:

Das Modell hat eine Eigenschaft vom TypIEnumerable<T>Sie übergeben diese Eigenschaft anHtml.EditorFor() Verwenden der Überladung, die nur den Lambda-Ausdruck akzeptiertSie haben eine Editorvorlage für den TypT unter Views / Shared / EditorTemplates

Anschließend ruft die MVC-Engine automatisch die Editorvorlage für jedes Element in der angegebenen Reihenfolge auf und erstellt eine Liste der Ergebnisse.

Zum Beispiel, wenn es eine Modellklasse gibtOrder mit EigentumLines:

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

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

Und es gibt eine Ansicht Views / Shared / EditorTemplates / OrderLine.cshtml:

@model TestEditorFor.Models.OrderLine

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

Dann, wenn Sie anrufen@Html.EditorFor(m => m.Lines) Von der Ansicht der obersten Ebene erhalten Sie eine Seite mit Textfeldern für jede Bestellposition und nicht nur eine.

Wie Sie in der verknüpften Frage sehen können, funktioniert dies jedoch nur, wenn Sie diese bestimmte Überladung von verwendenEditorFor. Wenn Sie einen Vorlagennamen angeben (um eine Vorlage zu verwenden, die nicht nach dem Dateinamen benannt ist)OrderLine Klasse), dann findet die automatische Sequenzbehandlung nicht statt, und stattdessen tritt ein Laufzeitfehler auf.

An diesem Punkt müssen Sie das Modell Ihrer benutzerdefinierten Vorlage als deklarierenIEnumebrable<OrderLine> und manuell auf die eine oder andere Weise über seine Elemente iterieren, um alle auszugeben, z.

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

Und hier beginnen die Probleme.

Die auf diese Weise generierten HTML-Steuerelemente haben alle die gleichen IDs und Namen. Wenn Sie sie später POSTEN, kann der Model Binder kein Array von erstellenOrderLines, und das Modellobjekt, das Sie in der HttpPost-Methode im Controller erhalten, wirdnull.
Dies ist sinnvoll, wenn Sie sich den Lambda-Ausdruck ansehen - er verknüpft das zu konstruierende Objekt nicht wirklich mit einer Stelle im Modell, von der es stammt.

Ich habe verschiedene Möglichkeiten ausprobiert, um die Elemente zu durchlaufen, und es scheint, dass die einzige Möglichkeit darin besteht, das Modell der Vorlage als neu zu deklarierenIList<T> und zähle es mit auffor:

@model IList<OrderLine>

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

Dann in der Top-Level-Ansicht:

@model TestEditorFor.Models.Order

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

Hierdurch werden ordnungsgemäß benannte HTML-Steuerelemente bereitgestellt, die vom Modellordner bei einer Übergabe ordnungsgemäß erkannt werden.

Während dies funktioniert, fühlt es sich sehr falsch an.

Was ist der richtige, idiomatische Weg, um eine benutzerdefinierte Editor-Vorlage mit zu verwenden?EditorForunter Beibehaltung aller logischen Verknüpfungen, die es der Engine ermöglichen, HTML-Code zu generieren, der für den Modellordner geeignet ist?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage