Multiple Selections
Just to recap, an MVC Html.DropDownList
helper is rendered to the browser as an HTML <select>
element. They are mainly employed to provide the user with a means to select one of a number of options. Multiple selection select elements are useful when you want to provide your user with a means to choose more then one option but you do not want to use checkboxes, for example. You can enable multiple selection in one of two ways: you can add the multiple
attribute to the Html.DropDownList
helper via its htmlAttributes
parameter, or you can use the Html.ListBox
(or Html.ListBoxFor
) helper. Options can be passed to the helper in a number of forms: as an Enumerable<SelectListItem>
; as a SelectList
object or as a MultiSelectList
object:
using (var db = new NorthwindContext()) { var categories = db.Categories.Select(c => new { CategoryID = c.CategoryID, CategoryName = c.CategoryName }).ToList(); ViewBag.Categories = new MultiSelectList(categories, "CategoryID", "CategoryName"); return View(); }
@Html.DropDownList("CategoryId", (MultiSelectList)ViewBag.Categories, new { multiple = "multiple"}) @Html.ListBox("CategoryId", (MultiSelectList)ViewBag.Categories)
Both helpers will result in identical HTML:
<select id="CategoryId" multiple="multiple" name="CategoryId"> <option value="1">Beverages</option> <option value="2">Condiments</option> <option value="3">Confections</option> <option value="4">Dairy Products</option> <option value="5">Grains/Cereals</option> <option value="6">Meat/Poultry</option> <option value="7">Produce</option> <option value="8">Seafood</option> </select>
There aren't a lot of styling options for multiple select lists, but you can affect the number of list item initially visible by default (4) by setting a value for the size
attribute:
@Html.ListBox("CategoryId", (MultiSelectList)ViewBag.Categories, new { size = 8 })
When a multiple select control is posted to the server, the collection of selected values are processed by ASP.NET into a comma-separated list. The MVC model binding system quite happily sees this collection as an array. If the selected values can be parsed into ints, you can use an int
array to represent the posted values. The following image shows a select list generated from the code above being posted back to the server. The selected items have values of 1, 3 and 7, which are captured in the categoryId
parameter. The parameter name matches the name given to the DropDownList
.
Setting Selected Values
You often need to set the selected values of a multiple select control, such as in editing scenarios or if you want to provide the user with a default selection. You can achieve this in a number of ways depending on preference and the helper that you use to generate the multiple select control. The SelectList
class doesn't support setting multiple items as selected, so it is not an option, but you can use either the MultiSelectList
or a collection of SelectListItem
objects. The following code shows the selected values being set as 1, 3 and 7 when using the MultiSelectList
approach:
using (var db = new NorthwindContext()) { var categories = db.Categories.Select(c => new { CategoryID = c.CategoryID, CategoryName = c.CategoryName }).ToList(); ViewBag.Categories = new MultiSelectList(categories, "CategoryID", "CategoryName", new[]{1,3,7}); return View(); }
Here's the alternative approach that passes a List<SelectListItem>
to the view:
using (var db = new NorthwindContext()) { var selected = new[] { 1, 3, 7 }; var categories = db.Categories .AsEnumerable() .Select(c => new SelectListItem { Value = c.CategoryID.ToString(), Text = c.CategoryName, Selected = selected.Contains(c.CategoryID) }).ToList(); ViewBag.Categories = categories; return View(); }
The MultiSelectList
approach seems to win in terms of user-friendliness.
Html.ListBoxFor and view models
The Html.ListBoxFor
helper is the strongly typed version designed for use with view models. Here's a simple view model to illustrate how to use the ListBoxFor
helper:
public class CategoryViewModel { public int[] CategoryId { get; set; } public MultiSelectList Categories { get; set; } }
The view model class has two properties - an array of ints to represent the selected values and a MultiSelectList
to hold the options. Here is a snippet showing the view code:
@Html.ListBoxFor(model => model.CategoryId, Model.Categories, new { size = 8 })
And here is the code to populate the options:
using (var db = new NorthwindContext()) { var model = new CategoryViewModel(); var categories = db.Categories.Select(c => new { CategoryID = c.CategoryID, CategoryName = c.CategoryName }).ToList(); model.Categories = new MultiSelectList(categories, "CategoryID", "CategoryName"); model.CategoryId = new[] { 1, 3, 7 }; return View(model); }
In this example, I have explicitly set the view model's CategoryId
property with the array that holds the selected values. The ListBoxFor
helper will mark each of these options as selected in the rendered HTML. You can just as easily pass the integer array in to the MultiSelectList
method as shown earlier:
using (var db = new NorthwindContext()) { var model = new CategoryViewModel(); var categories = db.Categories.Select(c => new { CategoryID = c.CategoryID, CategoryName = c.CategoryName }).ToList(); model.Categories = new MultiSelectList(categories, "CategoryID", "CategoryName", new[] { 1, 3, 7 }); return View(model); }
The resulting HTML will be the same.
Enumerations as a source for options
ASP.NET MVC 5.1 saw the introduction of a new helper: Html.EnumDropDownListFor
. As a strongly typed helper, this works with enum
properties in view models. It takes the members of the enum and produces a select list with them, assigning the value to the option's value
attribute and the enumerator to the text. Here's an example of an enum
:
public enum Power { Coal = 1, Gas, Hydro, Nuclear, Solar, Wave, Wind }
This might be used to represent a selection of power generation options. Here's how it might appear as part of a view model:
public class PowerViewModel { public Power Power { get; set; } }
And this is how the helper is used to render the options in the view:
@model PowerViewModel <form method="post"> @Html.EnumDropDownListFor(model => model.Power) <div> <input type="submit" /> </div> </form>
By default, the option with a value of 0 is selected. In this case, the enum values were intialised at 1 so the helper added an option with a value of 0 and empty text and made it selected:
If you want another option to be selected, you can set that in the view model:
var model = new PowerViewModel(); model.Power = Power.Hydro; return View(model);
If you prefer a default option that says "Pick One" or similar, you can pass that value into the second argument for the helper method:
@Html.EnumDropDownListFor(model => model.Power, "Pick One")
If your enum starts at 0, this will result in an extra option with an empty value appearing in the list. However, the first enum (in my example, Coal
) will still be selected by default. If you start your enum from 1, the "Pick One" option will be generated with a value of 0, which will be selected by default and will also form a valid selection if you make the property required via the DataAnnotation [Required]
attribute. So what if you don't want the "Pick One" option being assigned a value and/or don't want the option with a value of 0 to be selected by default? You can solve both these problems by making the enum nullable in your view model:
public class PowerViewModel { public Power? Power { get; set; } }
And of course, you can still force the user to pick a valid value by adding the [Required]
attribute to the property in the view model.
Finally, to retrieve the selected value, you ensure that the enum is included in the parameter list belonging to the action method that the form posts to, either on its own or as part of a view model. Here's the selected value being caught by the debugger when the form is posted back to the controller:
Summary
This article completes my look at dropdownlists in ASP.NET MVC. It looks at how to manage multiple selections and explores the new helper introduced in MVC 5.1 to support the use of enumerations in dropdownlists. If you would like to review the more common uses of the DropDownList helpers, please take some time to read the first article.