2012-10-02 4 views
8

ho il seguente schema di classe in MVC:MVC - Modifica di un elenco di oggetti

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

ora creo una vista fortemente tipizzato in MVC di questo tipo e fare campi di testo modificabili per modificare ogni valore, nonché utilizzare un ciclo foreach per popolare i campi di testo per modificare gli elementi nell'elenco di alcuni oggetti.

quando invio al metodo httppost i valori singolari ritornano correttamente nell'oggetto reportmodel ma l'elenco non viene restituito nell'oggetto. Come dovrebbe essere fatto?

Quando dico HttpPost mi riferisco al metodo che MVC è distacco torna a

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

codice della vista per la pubblicazione l'elenco dei 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

Primo: Nitpicking: nel titolo: elenco, non acceso. Secondo: qual è il metodo httppost di cui si sta parlando? Stiamo parlando di Android qui? Per favore aggiungi quel tag per denotarlo. – bldoron

+6

Hai letto questo: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx –

+0

@KirillBestemyanov Questo non è esattamente quello che sto cercando dato che mi aspetto di riportarli nel modello di report non come parametri separati per la funzione – DMCApps

risposta

1

di riferimento di Kirill al blog di Scott Hanselman è corretto, ma lo stai leggendo troppo da vicino. Nell'esempio mostrato, passa la matrice al metodo di azione, ma potrebbe anche essere contenuta all'interno del modello principale. Lo stesso concetto vale.

Tuttavia, una cosa da sapere è che il modello predefinito non crea un'istanza delle classi annidate, quindi non creerà un'istanza della classe List, il che significa che sarà sempre nullo. Per risolvere questo problema, è necessario creare un'istanza della classe dell'elenco vuoto nel costruttore.

Questa è solo una parte del problema, anche se i dati devono essere formattati in modo corretto per consentire al raccoglitore modello di collegarlo. È qui che entra in contatto il post sul blog di Scott, in quanto fornisce il formato necessario affinché il raccoglitore modello riconosca i dati come un elenco.

Questo in genere viene gestito per te se si utilizza un EditorTemplate e si utilizza Html.EditorFor (m => m.Items) e quindi si è selezionato SomeItem.cshtml EditorTemplate. Questo riguarda i problemi di denominazione degli elementi della raccolta (purché si utilizzino anche gli helper fortemente tipizzati nel modello).

11

Non utilizzare ElementAt(1) nelle espressioni lambda => questo rovina i nomi dei campi di input. Per favore, leggi il post sul blog che Kirill ti ha suggerito.

Così si potrebbe utilizzare l'accesso indicizzato:

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> 
} 

Naturalmente, al fine di avere accesso indicizzatore alla collezione questo presuppone che la vostra proprietà items è dichiarato come sia List<SomeItem> o SomeItem[]. Se è un IEnumerable<SomeItem> non funzionerà. Quindi, semplicemente, modifica il tipo di questa proprietà sul tuo modello di vista.

+0

hmm Penso che il mio sia un oggetto IEnumerable perché sto usando un oggetto entità passato direttamente alla vista e credo che si aspetti un IEnumerable. Fondamentalmente devo creare un oggetto modelview, questo è un po 'indesiderabile perché ci sono circa 180 campi nel mio oggetto (nessuna scelta nel ridurlo perché non è il mio progetto lol). – DMCApps

+2

Hai 180 campi nel modulo e tutti sono richiesti dalla vista? Se questo è il caso, allora l'utilizzo di un modello di vista non apporterà molto beneficio. Quindi in questo caso potresti usare un modello di editor personalizzato. Non scrivere nessun ciclo 'for' nella vista. Basta sostituire l'intero ciclo con '@ Html.EditorFor (x => x.items)' e quindi definire un modello di editor personalizzato per la classe 'SomeItem' -' ~/Views/Shared/EditorTemplates/SomeItem.cshtml'. ASP.NET MVC invocherà automaticamente questo modello personalizzato per ogni elemento della raccolta di elementi, quindi il modello verrà fortemente digitato in '@model SomeItem' –

+1

Quindi all'interno del modello personalizzato inserire il markup con i div e utilizzare le seguenti espressioni:' @ Html.TextBoxFor (x => x.propertyOne), ... '. In questo caso l'helper genererà nomi appropriati per i campi di input. –