Encuadernación de modelos a una lista MVC 4

¿Hay un patrón para vincular un IList de elementos a la vista? Parece que tengo problemas con el HttpPost. Sé que Phil Haack escribió un buen artículo pero está fechado y dijo que podrían tener una solución con MVC 4.

Así es como lo hago si necesito un formulario que se muestra para cada artículo, y entradas para varias propiedades. Realmente depende de lo que bash hacer.

ViewModel se ve así:

public class MyViewModel { public List Persons{get;set;} } 

Vista (con BeginForm por supuesto):

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

Acción:

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

Tenga en cuenta que en la publicación posterior solo las propiedades que tenían entradas disponibles tendrán valores. Es decir, si la persona tuviera una propiedad .SSN, no estaría disponible en la acción posterior porque no era un campo en el formulario.

Tenga en cuenta que, por la forma en que funciona el enlace del modelo MVC, solo buscará identificaciones consecutivas. Por lo tanto, hacer algo como esto en el que ocultas condicionalmente un artículo hará que no vincule ningún dato después del quinto elemento, porque una vez que encuentra un espacio en los IDs, dejará de enlazarse. Incluso si hubiera 10 personas, solo obtendrías los primeros 4 en la devolución de datos:

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

Una solución limpia podría ser crear una clase genérica para manejar la lista, por lo que no necesita crear una clase diferente cada vez que la necesite.

 public class ListModel { public List Items { get; set; } public ListModel(List list) { Items = list; } } 

y cuando devuelve la Vista, simplemente tiene que hacer:

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

luego defina la lista en el modelo:

 @model ListModel 

y listo para ir:

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

~ Controlador

 namespace ListBindingTest.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { List tmp = new List(); tmp.Add("one"); tmp.Add("two"); tmp.Add("Three"); return View(tmp); } [HttpPost] public ActionResult Send(IList input) { return View(input); } } } 

~ Vista de índice fuertemente tipada

 @model IList @{ Layout = null; }     Index   
@using(Html.BeginForm("Send", "Home", "POST")) { @Html.EditorFor(x => x)
}

~ Strongly Typed Enviar vista

 @model IList @{ Layout = null; }     Send   
@foreach(var element in @Model) { @element
}

Esto es todo lo que tenía que hacer, cambiar su modelo MyViewModel a IList.