Vinculação de modelo a uma lista MVC 4

Existe um padrão para ligar um IList de itens para a exibição. Parece que estou tendo problemas com o HttpPost. Eu sei que o Phil Haack escreveu um artigo legal, mas é datado e ele disse que eles podem ter uma correção com o MVC 4.

É assim que faço se precisar de um formulário exibido para cada item e inputs para várias propriedades. Realmente depende do que estou tentando fazer.

ViewModel é assim:

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

Ver (com BeginForm claro):

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

Açao:

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

Observe que, nas propriedades de pós-retrocesso, somente as inputs disponíveis terão valores. Ou seja, se Person tivesse uma propriedade .SSN, ela não estaria disponível na ação de postagem porque não era um campo no formulário.

Note que a maneira como o modelo de binding do MVC funciona, ele só procura IDs consecutivos. Portanto, fazer algo assim em que você oculta condicionalmente um item fará com que ele não vincule nenhum dado após o quinto item, pois, uma vez encontrado um intervalo nos IDs, ele interromperá a vinculação. Mesmo que houvesse 10 pessoas, você só conseguiria os 4 primeiros no 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) } } 

Uma solução limpa poderia ser criar uma class genérica para manipular a lista, para que você não precise criar uma class diferente sempre que precisar.

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

e quando você retornar a Visualização, basta fazer simplesmente:

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

em seguida, defina a lista no modelo:

 @model ListModel 

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

~ Modo de Indexação Fortemente Digitado

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

~ Strongly Typed Enviar Vista

 @model IList @{ Layout = null; } < !DOCTYPE html>    Send   
@foreach(var element in @Model) { @element
}

Isso é tudo o que você tinha que fazer cara, mude seu modelo MyViewModel para IList.