The upside for this is that Asp.Net code is opensource, so I took a sneak peak in the upcomming MVC 3 source code to see what the DropDownListFor code looked like.
Lets cut to the chase.
for all kinds of select html variations MVC uses the SelectListItem class. We just need to subcass it and add a new string property named GroupKey. Here is the code fot that.
public class GroupedSelectListItem : SelectListItem
{
public string GroupKey { get; set; }
}
Then i took the helper overloads for DropDownListFor, renamed them to DropDownGroupListFor, and changed the selectlist parameter type to IEnumerable<GroupedSelectListItem>.
public static MvcHtmlString DropDownGroupListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<GroupedSelectListItem> selectList)
Finaly we just need to change a for loop inside the "GetSelectData" private method in order to take optgroup into consideration. Here is how it looks like.
foreach (var group in selectList.GroupBy(i => i.GroupKey)) {
listItemBuilder.AppendLine(string.Format("<optgroup label=\"{0}\">", group.Key));
foreach (GroupedSelectListItem item in group) {
listItemBuilder.AppendLine(ListItemToOption(item));
}
listItemBuilder.AppendLine("</optgroup>");
}
As requested here is a usage example. Say we have the following list of vehicles in our Model.
.. and the entity class looks like this
Now in our View we add the following statement.
<%: Html.DropDownGroupListFor(model => model.VehicleId,
Lookups.Vehicles.Select(v => new GroupedSelectListItem() {
GroupKey = v.Group,
Text = v.Description,
Value = v.Id.ToString()
}),
"---- select Vehicle ----")%>
Note that Lookups is a static helper class that gets the collection we need to bind to the dropdownlist.
public class Lookups
{
public static ICollection<Vehicle> Vehicles {
get {
ICollection<Vehicle> vehicles = null;
using (DBEntities context = new DBEntities()) {
vehicles = context.Vehicles.ToList();
}
return vehicles;
}
}
}
After that, we use a simple linq selection in order to transform our source collection in the form of List of GroupedSelectListItem. This is the format that the DropDownGroupListFor helper understands
If everything went according to plan then we expect to see something like this in the output:
You can download the code here (Updated: February 2011)