Below is an extension to the HtmlHelper. It is very similar to the EnumDropDownListFor extension from ASP.NET, but it sorts the SelectListItem by the item display name. It has a suggestive name: SortedEnumDropDownListFor for not conflicts with the original extension.
/// <summary>
///
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TEnum">The type of the value.</typeparam>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="expression">An expression that identifies the object that contains the properties to display</param>
/// <param name="initalValue">The unselected item initial value</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string initalValue, object htmlAttributes = null)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
Type baseEnumType = Enum.GetUnderlyingType(enumType);
List<SelectListItem> items = new List<SelectListItem>();
foreach (FieldInfo field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
{
string text = field.Name;
string value = Convert.ChangeType(field.GetValue(null), baseEnumType).ToString();
bool selected = field.GetValue(null).Equals(metadata.Model);
foreach (DisplayAttribute displayAttribute in field.GetCustomAttributes(true).OfType<DisplayAttribute>())
{
text = displayAttribute.GetName();
}
items.Add(new SelectListItem
{
Text = text,
Value = value,
Selected = selected
});
}
items = new List<SelectListItem>(items.OrderBy(s => s.Text));
items.Insert(0, new SelectListItem { Text = initalValue, Value = "" });
return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}
private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
{
Type realModelType = modelMetadata.ModelType;
Type underlyingType = Nullable.GetUnderlyingType(realModelType);
if (underlyingType != null)
{
realModelType = underlyingType;
}
return realModelType;
}
If you don't want to bother with the unselected item intitia, just build a overload like this:
public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes = null)
{
MvcHtmlString helper = SortedEnumDropDownListFor(htmlHelper, expression, string.Empty, htmlAttributes);
return helper;
}
And you are good to go. I hope it helps.
EnumDropDownListFor
here and here and modify the signature to include a parameter that is a collection of excluded values, then in theEnumHelper.GetSelectList()
method, ignore items that are in the excluded values. – Arthropod