ASP.NET Bind to IEnumerable

asp.netasp.net-mvcmodel-bindingpostback

I'm passing a the type IEnumerable to my view, and for each item I output a html.textbox to enter the details into.

When I post this back to my controller, the collection is empty and I can't see why.

    public class Item
    {
        public Order Order { get; set; }
        public string Title { get; set; }
        public double Price { get; set; }
    }

My Get method:

public ActionResult AddItems(Order order)
    {
        Item itemOne = new Item
        {
            Order = order
        };

        Item itemTwo = new Item
        {
            Order = order,
        };

        IList<Item> items = new List<Item> { itemOne, itemTwo };

        return View(items);
    }

The View:

            <% int i = 0; foreach (var item in Model)
           { %>

            <p>
                <label for="Title">Item Title:</label>
                <%= Html.TextBox("items[" + i + "].Title") %>
                <%= Html.ValidationMessage("items[" + i + "].Title", "*")%>
            </p>
            <p>
                <label for="Price">Item Price:</label>
                <%= Html.TextBox("items[" + i + "].Price") %>
                <%= Html.ValidationMessage("items[" + i + "].Price", "*")%>
            </p>

        <% i++;
           } %>

The POST method:

 [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult AddItems(IEnumerable<Item> items)
    {
        try
        {

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

At the moment i just have a breakpoint on the post method to check what i'm gettin back.

Best Answer

Try adding this:

<input type="hidden" name="items.Index" value="<%=i%>" />

Further...

I took the liberty of changing how you do your for loop so that you no longer need to do the incrementing in the code, as I always find this a bit convoluted. This means that you would call the current item as:

<%= item.Current %>

And you access the current index of the loop with:

<%= item.Index %>

So your view would look like this (although you never seem to use the current item anyway, just the index of it):

<% foreach(var item in Model.Select((x, i) => new { Current = x, Index = i }) { %>
  <p>
    <label for="Title">Item Title:</label>
    <input type="hidden" name="items.Index" value="<%= item.Index %>" />
    <%= Html.TextBox("items[" + item.Index + "].Title") %>
    <%= Html.ValidationMessage("items[" + item.Index + "].Title", "*")%>
  </p>
  <p>
    <label for="Price">Item Price:</label>
    <%= Html.TextBox("items[" + item.Index + "].Price") %>
    <%= Html.ValidationMessage("items[" + item.Index + "].Price", "*")%>
  </p>
<% } %>