The HtmlHelper.ListBoxFor and HtmlHelper.listBox methods have a design bug. A very frustrating and annoying bug, as no error is thrown, it simply doesn't correctly display the selected values.
I'm not looking for an answer, as I've already figure it out. I'm posting so others don't have to spend hours debugging.
Simply put, whomever designed these HtmlHelpers messed up.
Here is what you need to know and understand.
1) The selectedValues parameter must be populated with a collection of key values only. It cannot be a collection of the selected objects, as the HtmlHelper does not apply the dataValueField to this collection for you.
2) If using the ListBox you cannot set the name parameter the same as a Model property. Also you cannot name the ViewBag property that will contain the collection of items the same as the Model property.
3) If using the ListBoxFor it gets even more wonky. You should name the ViewBag property that will contain the collection of items the same as the Model property name. Now when you use the ListBoxFor within the View you must use a ViewBag property that does not exist (this is important!). The HtmlHelper.ListBoxFor will look automatically for a ViewBag property with the assigned Model property name.
Code Example below;
public class Student { public string Id { get; set; } public string Name { get; set; } public Student(string id, string name) { this.Id = id; this.Name = name; } } public class Room { public List<Student> Students { get; set; } } public ActionResult() { var students = new List<Student>() { new Student("1","test1"), new Student("2","test2"), new Student("3","test3") } var room = new Room(); room.Students = students.Skip(2).Take(2); // Make sure the selected list only contains the Ids. var selected = room.Students.Select(s => s.Id); // Make sure the ViewBag property is the same name as the Model property. this.ViewBag.Students = new MultiSelectList(students, "Id", "Name", selected); return View(room); } // In the View @model Room @Html.ListBoxFor(m => m.Students, this.ViewBag.JustMakeUpANameHere as MultiSelectList)
I've tested this scenario. It's strange, but it works. So for those of you losing your hair trying to figure out why it refuses to preselect the selected items, now you know how to workaround the issue.