2012-10-02 19 views
8

Ich habe die folgende Klasse Layout in MVC:MVC - Bearbeiten einer Liste von Objekten

public class ReportModel 
{ 
    List<SomeItem> items; 
    string value; 
    string anotherValue; 
} 

jetzt erstelle ich eine stark typisierte Ansicht in MVC dieser Art und machen editierbaren Textfeldern jeden Wert zu bearbeiten sowie Verwenden Sie eine foreach-Schleife, um Textfelder zu füllen, um die Elemente in der Liste eines Elements zu bearbeiten.

Wenn ich die Methode httppost übergebe, kommen die singulären Werte im reportmodel-Objekt wieder gut, aber die Liste wird im Objekt nicht zurückgegeben. Wie soll das gemacht werden?

Wenn ich sage, Httppost Ich beziehe mich auf die Methode, die MVC entsendet zurück

[HttpPost] 
public ActionResult EditReport(ReportModel report) 
{ 
    // Save the report in here after the update on the UI side 
} 

Ansicht Code für die Buchung die Liste der someitem

if (Model.items != null && Model.items.Count > 0) 
{ 
    for (int i = 0; i < Model.items.Count; i++) 
    {     
     <div class="editrow"> 
      <div class="edititem"> 
       <div class="editor-label"> 
        @Html.LabelFor(m => m.items.ElementAt(i).propertyOne) 
       </div> 
       <div class="editor-field"> 
        @Html.TextBoxFor(m => m.items.ElementAt(i).propertyOne) 
        @Html.ValidationMessageFor(m => m.items.ElementAt(i).propertyOne) 
       </div> 
      </div> 
      <div class="edititem"> 
       <div class="editor-label"> 
        @Html.LabelFor(m => m.items.ElementAt(i).propertyTwo) 
       </div> 
       <div class="editor-field"> 
        @Html.TextBoxFor(m => m.items.ElementAt(i).propertyTwo) 
        @Html.ValidationMessageFor(m => m.items.ElementAt(i).propertyTwo) 
       </div> 
      </div> 
      <div class="edititem"> 
       <div class="editor-label"> 
        @Html.LabelFor(m => m.items.ElementAt(i).propertyThree) 
       </div> 
       <div class="editor-field"> 
        @Html.TextBoxFor(m => m.items.ElementAt(i).propertyThree) 
        @Html.ValidationMessageFor(m => m.items.ElementAt(i).propertyThree) 
       </div> 
      </div> 
     </div> 
    } 
} 
+0

Zuerst: Nitpicking: Im Titel: Liste, nicht beleuchtet. Zweitens: Was ist die httppost-Methode, von der Sie sprechen? Sprechen wir Android hier? Fügen Sie dieses Tag hinzu, um es zu bezeichnen. – bldoron

+6

Haben Sie das gelesen: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx –

+0

@KirillBestemyanov Das ist nicht ganz das, was ich suche, da ich erwarte, sie im Berichtsmodell nicht als separate Parameter zu erhalten die Funktion – DMCApps

Antwort

1

Kirill Verweis auf Scott Hanselman Blog-Eintrag ist richtig, aber du liest es zu eng. Im gezeigten Beispiel übergibt er das Array an die Aktionsmethode, könnte aber ebenso gut im übergeordneten Modell enthalten sein. Das gleiche Konzept gilt.

Eine Sache zu wissen ist jedoch, dass der Standardmodellbinder keine verschachtelten Klassen instanziiert, sodass keine Instanz der List-Klasse erstellt wird, was bedeutet, dass sie immer null ist. Um dies zu beheben, müssen Sie die leere Listenklasse im Konstruktor instanziieren.

Dies ist jedoch nur ein Teil des Problems, da die Daten für die Bindung des Modellbinders korrekt formatiert werden müssen. Dies ist der Punkt, an dem der Blogpost von Scott eingeht, da er das Format bereitstellt, das der Modellbinder benötigt, um die Daten als Liste zu erkennen.

Dies wird normalerweise für Sie behandelt, wenn Sie ein EditorTemplate verwenden und Html.EditorFor (m => m.Items) und dann eine SomeItem.cshtml EditorTemplate verwenden. Hier geht es um die Benennung von Sammlungselementen (sofern Sie auch stark typisierte Helfer in der Vorlage verwenden).

11

Verwenden Sie in Ihren Lambda-Ausdrücken nicht ElementAt(1) => dies ruiniert Ihre Eingabefeldnamen. Bitte lies den Blogpost, den Kirill dir vorgeschlagen hat.

So könnte man einen Index den Zugriff verwenden:

for (int i = 0; i < Model.items.Count; i++) 
{     
    <div class="editrow"> 
     <div class="edititem"> 
      <div class="editor-label"> 
       @Html.LabelFor(m => m.items[i].propertyOne) 
      </div> 
      <div class="editor-field"> 
       @Html.TextBoxFor(m => m.items[i].propertyOne) 
       @Html.ValidationMessageFor(m => m.items[i].propertyOne) 
      </div> 
     </div> 
     <div class="edititem"> 
      <div class="editor-label"> 
       @Html.LabelFor(m => m.items[i].propertyTwo) 
      </div> 
      <div class="editor-field"> 
       @Html.TextBoxFor(m => m.items[i].propertyTwo) 
       @Html.ValidationMessageFor(m => m.items[i].propertyTwo) 
      </div> 
     </div> 
     <div class="edititem"> 
      <div class="editor-label"> 
       @Html.LabelFor(m => m.items[i].propertyThree) 
      </div> 
      <div class="editor-field"> 
       @Html.TextBoxFor(m => m.items[i].propertyThree) 
       @Html.ValidationMessageFor(m => m.items[i].propertyThree) 
      </div> 
     </div> 
    </div> 
} 

Natürlich um Indexer-Zugriff auf die Sammlung zu haben, dies setzt voraus, dass Ihr items Eigenschaft entweder als List<SomeItem> deklariert wird oder SomeItem[]. Wenn es ein IEnumerable<SomeItem> ist, wird es nicht funktionieren. Ändern Sie einfach den Typ dieser Eigenschaft in Ihrem Ansichtsmodell.

+0

hmm Ich denke, dass meine ist ein IEnumerable, weil ich ein Objekt der Entität direkt an die Ansicht übergeben und ich glaube, es erwartet ein IEnumerable. Im Grunde muss ich ein Modelview-Objekt erstellen, das ist irgendwie unerwünscht, da es in meinem Objekt etwa 180 Felder gibt (keine Wahl, es zu reduzieren, denn es ist nicht mein Projekt, lol). – DMCApps

+2

Sie haben 180 Felder in Ihrem Formular und alle von ihnen werden für die Ansicht benötigt? Wenn dies der Fall ist, wird die Verwendung eines Ansichtsmodells tatsächlich nicht viel Nutzen bringen. In diesem Fall könnten Sie eine benutzerdefinierte Editorvorlage verwenden. Schreibe keine 'for'-Schleifen in die Ansicht. Ersetzen Sie einfach die gesamte Schleife durch '@ Html.EditorFor (x => x.items)' und definieren Sie dann eine benutzerdefinierte Editor-Vorlage für die 'SomeItem'-Klasse -' ~/Views/Shared/EditorTemplates/SomeItem.cshtml'. ASP.NET MVC wird automatisch diese benutzerdefinierte Vorlage für jedes Element der Elementauflistung aufrufen, so dass die Vorlage stark auf '@model SomeItem' getippt wird. –

+1

Dann innerhalb der benutzerdefinierten Vorlage setzen Sie das Markup mit den divs und verwenden Sie die folgenden Ausdrücke:' @ Html.TextBoxFor (x => x.propertyOne), ... '. In diesem Fall generiert der Helfer korrekte Namen für die Eingabefelder. –

Verwandte Themen