views:

1476

answers:

6

Take the example classes below. I want to display the customer and two addresses (from a LIST) on a form. Does the model binder in MVC beta support this or will I have to write my own custom binder?

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Address> Addresses { get; set; }

    public Customer()
    {
        Addresses = new List<Address>();
    }

}

public class Address
{
    public int Line1 { get; set; }
    public int Line2 { get; set; }
    public int City { get; set; }
    public int State { get; set; }
    public int Zip { get; set; }
}

How would you code the fields? Like this?

<!-- some HTML formatting -->
<%= Html.TextBox("customer.address.line1", ViewData.Customer.Address[0].Line1)%>
<!-- some more HTML formatting -->
<%= Html.TextBox("customer.address.line1", ViewData.Customer.Address[1].Line1)%>
<!-- end of HTML form formatting -->
A: 

You can pass an object list with ViewData like that, but you need to change some of the lines. Read more here:

http://weblogs.asp.net/scottgu/archive/2007/12/06/asp-net-mvc-framework-part-3-passing-viewdata-from-controllers-to-views.aspx

and here:

http://stackoverflow.com/questions/314933/aspnet-mvc-how-do-i-pass-a-list-from-a-class-in-model-to-a-repeater-in-a-view

Hope this helps


Edit


If you use a model, you need to set up the DataContext first and select the list, but sure you can use the classes generated if you use LINQ.

Filip Ekberg
+4  A: 

I've never tried it, but see this post, it's about model binding to a list, maybe it can help you.

Eduardo Campañó
A: 

I defined a similar object. I followed the post on binding to a list as referenced above, While the binding works,I was unable to use the Bind whitelist or blacklist in the controller's action parameter. THe model is an IList

zsharp
+1  A: 

Use MvcContrib's NameValueDeserializer to make it simpler. Let's assume that your page derives from ViewPage<Customer>. You can do this:

<%= Html.TextBox("Address[0].Line1", ViewData.Model.Address[0].Line1)%>
<%= Html.TextBox("Address[1].Line1", ViewData.Model.Address[1].Line1)%>

And this:

public ActionResult Save([Deserialize]Customer customer)

And the customer will be deserialized from the form post with the address collection populated. Your indexes do not have to be in sequence -- this supports cases where you want to remove rows on the client side before the post occurs.

In the case that you are deserializing something from the view data dictionary (instead of the Model), then the syntax is like [Deserialize("customer")], where "customer" is the prefix.

You might find this blog post interesting and relevant.

Tim Scott
+1  A: 

Just to make this complete. It's important that you use the hidden fields with the name Index. So my code above becomes this:

<!-- some HTML formatting -->
<%= Html.Hidden("customer.address.Index", 0) %>
<%= Html.TextBox("customer.address[0].line1", ViewData.Customer.Address[0].Line1)%>
<!-- some more HTML formatting -->
<%= Html.Hidden("customer.address.Index", 1) %>
<%= Html.TextBox("customer.address[1].line1", ViewData.Customer.Address[1].Line1)%>
<!-- end of HTML form formatting -->

It works like a charm!

37Stars
I think I'll need something like this in the near future, nice question.
Eduardo Campañó
A: 

Thanks. Works really well.

harshalj