views:

1840

answers:

4

I have the following code in my view:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

<%= Html.ListBox("MultiSelectList", 
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

The only difference is that the first helper is strongly typed (ListBoxFor), and it fails to show the selected items (1,2), even though the items appear in the list, etc. The simpler ListBox is working as expected.

I'm obviously missing something here. I can use the second approach, but this is really bugging me and I'd like to figure it out.

For reference, my model is:

public class ProjectEditModel
{
    public Project Project { get; set; }
    public IEnumerable<Project> Projects { get; set; }
    public IEnumerable<Client> Clients { get; set; }
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
    public ProjectSlide SelectedSlide { get; set; }
}

Update

I just changed the ListBox name to Project.Categories (matching my model) and it now FAILS to select the item.

<%= Html.ListBox("Project.Categories",
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

I'm obviously not understanding the magic that is happening here.

Update 2

Ok, this is purely naming, for example, this works...

<%= Html.ListBox("Project_Tags",
new MultiSelectList(Model.Tags, "Id", "Name", Model.Project.Tags.Select(t => t.Id)))%>

...because the field name is Project_Tags, not Project.Tags, in fact, anything other than Tags or Project.Tags will work. I don't get why this would cause a problem (other than that it matches the entity name), and I'm not good enough at this to be able to dig in and find out.

+1  A: 

Did you try this?

c.Project.Categories.Add(1);
c.Project.Categories.Add(2);

Html.ListBoxFor(c => c.Project.Categories,new MultiSelectList(Model.Categories, "Id", "Name"))%>

Remember that values can be overwritten by values stored in ModelState.

LukLed
I don't see where you are providing the selected values to the ListBox helper?I think it requires IEnumerable selectedValues, like: new MultiSelectList(Model.Categories, "Id", "Name", Model.Project.Categories), where Model.Project.Categories is an IEnumerable list of selectedValues. I've done quite a few variations on this, including Model.Project.Categories.Select(p=>p.Id), I have also confirmed that the collection has Category objects.
Roger Rogers
Sorry. I was wrong, it doesn't work. What type is `Model.Categories.Id`?
LukLed
Id (int) is a property of the Category class.
Roger Rogers
+1  A: 

Although this isn't an answer to your main question, it is worth noting that when MVC generates names it will turn something like Project.Tags into Project_Tags, replacing periods with underscores.

The reason that it does this is because a period in an element ID would look like an element named Project with a class of Tags to CSS. Clearly a bad thing, hence the translation to underscores to keep behaviour predictable.

In your first example,

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

the listbox is attempting to bind to Model.Project.Categories for your strongly typed Model which has been provided to the page (using the lambda notation). I'm not sure what the second parameter in the ListBoxFor is doing though.

What is the Model that is being passed to the page?

Alex White
At your request, I've added my model to the question.I'm aware that MVC changes the Id to Id="Project_Tags", but not so with the name, it remains "Project.Tags", and the name is what is posted back to the action, and therefore, I guess the part that is causing trouble, hence, if I change to Project_Tags, for the name property, it works. I'm just surprised there is even a strongly typed listboxfor helper if it really can't be used for multiselect lists!Thanks for your assistance!
Roger Rogers
+1  A: 

Try this

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", Model.Project.Tags.Select(
                                                                                 x =>
                                                                                 new SelectListItem()
                                                                                     {
                                                                                         Selected = true,
                                                                                         Text = x.TEXT,
                                                                                         Value = x.ID.ToString()
                                                                                     }).ToList())

))%>
Alex
+1  A: 

I have also been stuck with this exact same issue and encountered the same problem with ListBox and ListBoxFor.

No matter what I do, I cannot get selections to occur on the ListBoxFor. If I change to the ListBox and name it something OTHER than the property name of the data I am binding to, selections occur.

But then because I'm not using ListBoxFor and the data is sitting inside a model class (Model.Departments) for example, I don't get model binding on the way back to my controller and hence the property is null.

EDIT I found a solution posted by someone else here; http://stackoverflow.com/questions/3194143/challenges-with-selecting-values-in-listboxfor/3195986#3195986

Joshua Hayes
Darn, I wish I could remember the fix for this. If I remember correctly, it isn't as elegant as I'd like. There is an obscure behavior that is happening with model binding that causes your bind to be overridden. Not nice. If I can find an example I will share.
Roger Rogers