2013-03-13 16 views
24

C'è un modello per associare un IList di elementi alla vista. Mi sembra di avere problemi con HttpPost. So che Phil Haack ha scritto un buon articolo ma è datato e ha detto che potrebbe avere una correzione con MVC 4.Associazione modello a un elenco MVC 4

+0

Si prega di considerare l'aggiunta di ulteriori dettagli, incluso codice della formica e link alla tua domanda per renderlo più chiaro. Ecco una buona lista di controllo per iniziare: http://tinyurl.com/so-list – mellamokb

+0

Associazione di una lista a una vista. Cosa non è chiaro su questo? – Karthik

+1

Ci sono delle variazioni a seconda di come appare il tuo modulo. Qualche codice di visualizzazione potrebbe essere d'aiuto. – AaronLS

risposta

46

Ecco come lo faccio se ho bisogno di un modulo visualizzato per ciascun elemento e di input per varie proprietà. Dipende davvero da cosa sto cercando di fare però.

ViewModel si presenta così:

public class MyViewModel 
{ 
    public List<Person> Persons{get;set;} 
} 

View (con BeginForm ovviamente):

@model MyViewModel 


@for(int i = 0; i < Model.Persons.Count(); ++i) 
{ 
    @Html.HiddenFor(m => m.Persons[i].PersonId) 
    @Html.EditorFor(m => m.Persons[i].FirstName) 
    @Html.EditorFor(m => m.Persons[i].LastName)   
} 

Azione:

[HttpPost]public ViewResult(MyViewModel vm) 
{ 
... 

notare che il palo solo le proprietà che avevano ingressi disponibile avrà valori. Ad esempio, se Persona ha una proprietà .SSN, non sarebbe disponibile nell'azione post perché non era un campo nel modulo.

Si noti che il modo in cui l'associazione modello MVC funziona, sarà solo alla ricerca di ID consecutivi. Quindi, fare qualcosa del genere in cui si nasconde un oggetto in modo condizionato causerà il non vincolo di dati dopo il quinto elemento, perché una volta rilevato uno spazio negli ID, smetterà di legarsi. Anche se ci fossero 10 persone, si ottiene solo il primo 4 sul postback:

@for(int i = 0; i < Model.Persons.Count(); ++i) 
{ 
    if(i != 4)//conditionally hide 5th item, 
    { //but BUG occurs on postback, all items after 5th will not be bound to the the list 
     @Html.HiddenFor(m => m.Persons[i].PersonId) 
     @Html.EditorFor(m => m.Persons[i].FirstName) 
     @Html.EditorFor(m => m.Persons[i].LastName)   
    } 
} 
+1

Uso mvc 5.1 e al posto di '++ 1' ho dovuto farlo in questo modo:' @ {++ i; } ', all'interno di un blocco' @foreach() '. – Yustme

+0

@Yustme Forse, potrebbe anche esserci stato se avessi i tag HTML, avresti bisogno di '@ {}' per riportare quel contesto al codice C#. Ma buon consiglio in entrambi i casi. – AaronLS

+5

Dichiarare "i" e quindi usare un foreach è piuttosto brutto specialmente quando abbiamo FOR LOOPS. Inoltre, si prega di non utilizzare una specifica implementazione di List a meno che non sia realmente necessario. –

3

~ controller

namespace ListBindingTest.Controllers 
{ 
    public class HomeController : Controller 
    { 
     // 
     // GET: /Home/ 

     public ActionResult Index() 
     { 
      List<String> tmp = new List<String>(); 
      tmp.Add("one"); 
      tmp.Add("two"); 
      tmp.Add("Three"); 
      return View(tmp); 
     } 

     [HttpPost] 
     public ActionResult Send(IList<String> input) 
     { 
      return View(input); 
     }  
    } 
} 

~ fortemente tipizzato Indice del

@model IList<String> 

@{ 
    Layout = null; 
} 

<!DOCTYPE html> 

<html> 
<head> 
<meta name="viewport" content="width=device-width" /> 
<title>Index</title> 
</head> 
<body> 
    <div> 
    @using(Html.BeginForm("Send", "Home", "POST")) 
    { 
     @Html.EditorFor(x => x) 
     <br /> 
     <input type="submit" value="Send" /> 
    } 
    </div> 
</body> 
</html> 

~ fortemente tipizzati Invia Visualizza

@model IList<String> 

@{ 
    Layout = null; 
} 

<!DOCTYPE html> 

<html> 
<head> 
<meta name="viewport" content="width=device-width" /> 
<title>Send</title> 
</head> 
<body> 
    <div> 
    @foreach(var element in @Model) 
    { 
     @element 
     <br /> 
    } 
    </div> 
</body> 
</html> 

Questo è tutto ciò che dovevi fare, cambiare il suo modello MyViewModel in IList.

+0

Steve, grazie per le informazioni, questo funziona bene. Il mio problema, forse non l'ho spiegato, è stato l'associazione di una lista dinamica. Sanderson lo inchioda in questo post http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ – Karthik

+0

@JT Non importa se io digitare staticamente l'elenco nel controller o acquisirlo da un database o da un file. Da dove proviene la lista è irrilevante per il modello di rilegatura. –

+1

Il mio problema era con HttpPost. Quando una lista di oggetti cambia nella vista, i valori non vengono pubblicati correttamente. Questo è ciò che Sanderson ha affrontato e sto usando il suo metodo. Il team MVC lo sa e il metodo di Sanderson è il migliore che abbia mai visto. Mi scuso con tutti per non essere stato chiaro. – Karthik

6

Una soluzione pulita potrebbe essere creare una classe generica per gestire l'elenco, quindi non è necessario creare una classe diversa ogni volta che ne avete bisogno.

public class ListModel<T> 
{ 
    public List<T> Items { get; set; } 

    public ListModel(List<T> list) { 
     Items = list; 
    } 
} 

e quando si torna la vista non vi resta che fare semplicemente:

List<customClass> ListOfCustomClass = new List<customClass>(); 
//Do as needed... 
return View(new ListModel<customClass>(ListOfCustomClass)); 

indicare la lista nel modello:

@model ListModel<customClass> 

e pronto a partire:

@foreach(var element in Model.Items) { 
    //do as needed... 
} 
Problemi correlati