2013-03-13 10 views
24

Gibt es ein Muster, um eine IList von Elementen an die Ansicht zu binden. Ich habe Probleme mit der HttpPost. Ich weiß, Phil Haack schrieb einen schönen Artikel, aber es ist veraltet und er sagte, sie könnten eine Reparatur mit MVC 4 haben.Modellbindung an eine Liste MVC 4

+0

Bitte berücksichtigen Sie das Hinzufügen weiterer Details, einschließlich relev Ant-Code und Links zu Ihrer Frage, um es klarer zu machen. Hier ist eine gute Checkliste für den Einstieg: http://tinyurl.com/so-list – mellamokb

+0

Binden einer Liste an eine Ansicht. Was ist daran nicht klar? – Karthik

+1

Es gibt Variationen, je nachdem wie Ihre Form aussieht. Ein gewisser View-Code würde helfen. – AaronLS

Antwort

46

So mache ich es, wenn ich ein Formular für jedes Element angezeigt und Eingaben für verschiedene Eigenschaften benötigt. Wirklich hängt davon ab, was ich versuche zu tun.

Ansichtsmodell sieht wie folgt aus:

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

Ansicht (mit Begin natürlich):

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

Aktion:

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

Beachten Sie, dass auf Post zurück Eigenschaften nur die Eingänge hatte verfügbar wird Werte haben. Das heißt, wenn die Person eine .SSN-Eigenschaft hätte, wäre sie in der Post-Aktion nicht verfügbar, weil sie kein Feld im Formular war.

Beachten Sie, dass die Modellbindung von MVC nur nach fortlaufenden IDs sucht. Wenn Sie also etwas so tun, dass Sie ein Element bedingungslos ausblenden, werden nach dem 5. Element keine Daten gebunden, da es nach dem Auffinden einer Lücke in den IDs aufhört zu binden. Auch wenn es 10 Leute waren, würden Sie nur die ersten 4 auf der Postbacks erhalten:

@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

Ich benutze mvc 5.1 und anstelle von '++ 1' musste ich es so machen:' @ {++ i; } ', in einem' @foreach() 'Block. – Yustme

+0

@Yustme Vielleicht wäre es auch gewesen, wenn du HTML-Tags hättest, würdest du den '@ {}' brauchen, um diesen Kontext auf C# -Code zurückzusetzen. Aber guter Tipp in beide Richtungen. – AaronLS

+5

"i" zu deklarieren und dann foreach zu benutzen, ist ziemlich hässlich, besonders wenn wir FOR LOOPS haben. Bitte verwenden Sie auch keine spezifische List-Implementierung, es sei denn, Sie müssen dies wirklich tun. –

3

~ Regler

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

~ stark typisierten Übersicht

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

~ stark typisierten Senden Ansicht

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

Das war alles, was Sie tun mussten, ändern Sie sein MyViewModel-Modell zu IList.

+0

Steve, danke für die Info, das funktioniert gut. Mein Problem, vielleicht habe ich nicht erklärt, war das Binden einer dynamischen Liste. Sanderson nagelt es in diesem Beitrag http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/ – Karthik

+0

@JT Es spielt keine Rolle, wenn ich Geben Sie die Liste statisch in den Controller ein oder wählen Sie sie aus einer Datenbank oder Datei. Wo die Liste herkommt, ist für die Modellbindung irrelevant. –

+1

Mein Problem war mit HttpPost. Wenn sich eine Liste von Objekten in der Ansicht ändert, werden die Werte nicht korrekt gebucht. Das ist, was Sanderson angesprochen hat und ich benutze seine Methode. Das MVC-Team weiß das und Sandersons Methode ist die beste, die ich je gesehen habe. Ich entschuldige mich bei allen dafür, dass sie nicht klar sind. – Karthik

6

Eine saubere Lösung könnte eine generische Klasse zum Behandeln der Liste erstellen, so dass Sie nicht jedes Mal eine andere Klasse erstellen müssen, wenn Sie sie benötigen.

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

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

und wenn Sie die Ansicht zurückkehren müssen Sie nur einfach tun:

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

dann die Liste im Modell definieren:

@model ListModel<customClass> 

und bereit zu gehen:

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