views:

574

answers:

2

This is my first question, and it is probably a poor one, so please be gentle.

Working on my first ASP.Net MVC2 web app recently, I came across some issues when I needed to select multiple values in a list box. I worked around it with some jQuery, but went ahead and put together some very simple code to demonstrate. I'm using EF for the model, with two entities - Customers and HelpDeskCalls:

Controller:

 public ActionResult Edit(int id)
    {
        Customer currCustomer = ctx.Customers.Include("HelpDeskCalls").Where(c => c.ID == id).FirstOrDefault();
        List<HelpDeskCall> currCustCalls = (ctx.HelpDeskCalls.Where(h => h.CustomerID == id)).ToList();
        List<SelectListItem> currSelectItems = new List<SelectListItem>();
        List<String> selectedValues = new List<string>();
        foreach (HelpDeskCall currCall in currCustCalls)
        {
            bool isSelected = (currCall.ID % 2 == 0) ? true : false;
            //Just select the IDs which are even numbers...
            currSelectItems.Add(new SelectListItem() { Selected = isSelected, Text = currCall.CallTitle, Value = currCall.ID.ToString() });
            //add the selected values into a separate list as well...
            if (isSelected)
            {
                selectedValues.Add(currCall.ID.ToString());
            }
        }
        ViewData["currCalls"] = (IEnumerable<SelectListItem>) currSelectItems;
        ViewData["currSelected"] = (IEnumerable<String>) selectedValues;
        return View("Edit", currCustomer);
    }

View:

<div class="editor-field">
            <%: Html.ListBoxFor(model => model.HelpDeskCalls, new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable) ViewData["currSelected"]), new { size = "12" })%>       
            <%: Html.ListBoxFor(model => model.HelpDeskCalls, ViewData["currCalls"] as IEnumerable<SelectListItem>, new { size = "12"}) %>
            <%: Html.ListBox("Model.HelpDeskCalls", new MultiSelectList(Model.HelpDeskCalls, "ID", "CallTitle", (IEnumerable)ViewData["currSelected"]), new { size = "12"}) %>      
            <%: Html.ValidationMessageFor(model => model.HelpDeskCalls) %>
</div>

For this sample, I'm just selecting HelpDeskCall.IDs which are even. I'm trying two different syntaxes for ListBoxFor: One uses an IEnumerable of values for selections, one using an IEnumerable of SelectListItems. By default, when I run this code, no selections are made to either ListBoxFor, but the non-strongly typed ListBox selects correctly.

I read this post on ASP.Net and this thread on SO, but no joy. In fact, if I add the override ToString() to my HelpDeskCall class (as suggested in the ASP.net thread) all values are selected, which isn't right either.

If someone could shed some light on how this should work (and what I'm missing or doing wrong), this then neophyte would be very grateful.

John

+2  A: 

Here's an example illustrating the strongly typed version:

Model:

public class MyViewModel
{
    public int[] SelectedItemIds { get; set; }
    public MultiSelectList Items { get; set; }
}

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Preselect items with id 1 and 3
        var selectedItemIds = new[] { 1, 3 };

        var model = new MyViewModel
        {
            Items = new MultiSelectList(
                new[] 
                {
                    // TODO: Fetch from your repository
                    new { Id = 1, Name = "item 1" },
                    new { Id = 2, Name = "item 2" },
                    new { Id = 3, Name = "item 3" },
                }, 
                "Id", 
                "Name", 
                selectedItemIds
            )
        };

        return View(model);
    }
}

View:

<%: Html.ListBoxFor(x => x.SelectedItemIds, Model.Items) %>
Darin Dimitrov
Yup, that works. Thanks!
Mongo
Brilliant! I spent a while trying to get this to work. This worked for me also. Many thanks! Upvoting.
Joshua Hayes
A: 

I have found better workaround. Usual way to preselect select list:

@Html.ListBoxFor(
    model => model.Roles, 
    new MultiSelectList(db.Roles, "Id", "Name")
)
@Html.ValidationMessageFor(model => model.Roles)    

Doesn't work.., never ever any option is selected, until:

public ActionResult Edit(int id)
{
    var user = db.Users.Find(id);
    // this is workaround for http://aspnet.codeplex.com/workitem/4932?ProjectName=aspnet
    ViewData["Roles"] = user.Roles.Select(r => r.Id);
    return View(user);
}

Selected Roles has to be stored in ViewData, to workaround nasty bug.

Daniel Steigerwald