I wrote an HtmlHelper expression I use a lot of the time to put title tags into my dropdown lists like so:
public static HtmlString SelectFor
If you don't need the title attribute on individual options your code could be simplified to:
public static HtmlString SelectFor<TModel, TProperty, TIdProperty, TDisplayProperty, TListItem>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<TListItem> enumeratedItems,
Expression<Func<TListItem, TIdProperty>> idProperty,
Expression<Func<TListItem, TDisplayProperty>> displayProperty,
object htmlAttributes
) where TModel : class
{
var id = (idProperty.Body as MemberExpression).Member.Name;
var display = (displayProperty.Body as MemberExpression).Member.Name;
var selectList = new SelectList(enumeratedItems, id, display);
var attributes = new RouteValueDictionary(htmlAttributes);
return htmlHelper.DropDownListFor(expression, selectList, attributes);
}
and used like this:
@Html.SelectFor(
m => m.itemId,
Model.items,
id => id.itemId,
disp => disp.itemName,
null
)
And if you need the title
attribute, well, you will have to implement everything that the DropDownList helper does manually which could be quite of a pain. Here's an example of only a small portion of all the functionality:
public static class HtmlExtensions
{
private class MySelectListItem : SelectListItem
{
public string Title { get; set; }
}
public static HtmlString SelectFor<TModel, TProperty, TIdProperty, TDisplayProperty, TListItem>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<TListItem> enumeratedItems,
Expression<Func<TListItem, TIdProperty>> idProperty,
Expression<Func<TListItem, TDisplayProperty>> displayProperty,
Func<TListItem, string> titleProperty,
object htmlAttributes
) where TModel : class
{
var name = ExpressionHelper.GetExpressionText(expression);
var fullHtmlName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
var select = new TagBuilder("select");
var compiledDisplayProperty = displayProperty.Compile();
var compiledIdProperty = idProperty.Compile();
select.GenerateId(fullHtmlName);
select.MergeAttributes(new RouteValueDictionary(htmlAttributes));
select.Attributes["name"] = fullHtmlName;
var selectedValue = htmlHelper.ViewData.Eval(fullHtmlName);
var options =
from i in enumeratedItems
select ListItemToOption(
ItemToSelectItem(i, selectedValue, compiledIdProperty, compiledDisplayProperty, titleProperty)
);
select.InnerHtml = string.Join(Environment.NewLine, options);
return new HtmlString(select.ToString(TagRenderMode.Normal));
}
private static MySelectListItem ItemToSelectItem<TListItem, TIdProperty, TDisplayProperty>(TListItem i, object selectedValue, Func<TListItem, TIdProperty> idProperty, Func<TListItem, TDisplayProperty> displayProperty, Func<TListItem, string> titleProperty)
{
var value = Convert.ToString(idProperty(i));
return new MySelectListItem
{
Value = value,
Text = Convert.ToString(displayProperty(i)),
Title = titleProperty(i),
Selected = Convert.ToString(selectedValue) == value
};
}
private static string ListItemToOption(MySelectListItem item)
{
var builder = new TagBuilder("option");
builder.Attributes["value"] = item.Value;
builder.Attributes["title"] = item.Title;
builder.SetInnerText(item.Text);
if (item.Selected)
{
builder.Attributes["selected"] = "selected";
}
return builder.ToString();
}
}
and then use like this:
@Html.SelectFor(
m => m.itemId,
Model.items,
id => id.itemId,
disp => disp.itemName,
title => title.itemName + " " + title.itemDescription,
null
)