I am attempting to bind a list that is part of a larger view model without resorting to a custom model binder. When I use an editor template to build the list of inputs, the generated names are not in the correct format for the default binder to work.
Instead of Items[3].Id like I would expect it is Items.[3].Id. If I build the list without an editor template it works as expected.
Am I doing something obviously wrong or is this just a quirk of Html.Hidden and Html.TextBox?
public class ItemWrapper
{
[UIHint("ItemList")]
public IList<Item> Items { get; set; }
}
public class Item
{
public Guid Id { get; set; }
public string Name { get; set; }
public int Value { get; set; }
}
Index.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
<% using(Html.BeginForm())
{%>
<%:Html.EditorFor(m => m.Items) %>
<%}%>
</asp:Content>
ItemList.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<Mvc2Test.Models.Item>>" %>
<h4>Asset Class Allocation</h4>
<% if(Model.Count > 0) { %>
<table>
<tbody>
<% for(int i = 0; i < Model.Count; i++)
{%>
<tr>
<td><%: Model[i].Name%></td>
<td>
<%: Html.HiddenFor(m => m[i].Id) %>
<%: Html.TextBoxFor(m => m[i].Value) %>
</td>
</tr>
<%}%>
</tbody>
</table>
<%
}%>
Output
<tr>
<td>Item 4</td>
<td>
<input id="Items__3__Id" name="Items.[3].Id" type="hidden" value="f52a1f57-fca8-4bc5-a746-ee0cef4e05c2" />
<input id="Items__3__Value" name="Items.[3].Value" type="text" value="40" />
</td>
</tr>
Edit (Action Method)
public ActionResult Test()
{
return View(
new ItemWrapper
{
Items = new List<Item>
{
{ new Item { Id = Guid.NewGuid(), Name = "Item 1", Value = 10 } },
{ new Item { Id = Guid.NewGuid(), Name = "Item 2", Value = 20 } },
{ new Item { Id = Guid.NewGuid(), Name = "Item 3", Value = 30 } },
{ new Item { Id = Guid.NewGuid(), Name = "Item 4", Value = 40 } }
}
});
}
Edit #2
HttpPost Action
[HttpPost]
public ActionResult Test(ItemWrapper w)
{
if(w.Items == null)
Response.Write("Items was null");
else
Response.Write("Items found " + w.Items.Count.ToString());
return null;
}
Index.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h4>Does Not Work</h4>
<% using(Html.BeginForm("Test", "Home"))
{%>
<%:Html.EditorFor(m => m.Items) %>
<input type="submit" value-"Go" />
<%}%>
<h4>Does Work</h4>
<% using(Html.BeginForm("Test", "Home"))
{%>
<table>
<tbody>
<% for(int i = 0; i < Model.Items.Count; i++)
{%>
<tr>
<td><%: Model.Items[i].Name%></td>
<td>
<%: Html.HiddenFor(m => Model.Items[i].Id) %>
<%: Html.TextBoxFor(m => Model.Items[i].Value) %>
</td>
</tr>
<%}%>
</tbody>
</table>
<input type="submit" value-"Go" />
<%}%>
</asp:Content>