Binding an Enum to a DropDownList in MVC 4? [dupli

2019-01-31 13:24发布

This question already has an answer here:

I've been finding all over the place that the common way to bind Enums to DropDowns is through helper methods, which seems a bit overbearing for such a seemingly simple task.

What is the best way to bind Enums to DropDownLists in ASP.Net MVC 4?

7条回答
再贱就再见
2楼-- · 2019-01-31 13:29

In my Controller:

var feedTypeList = new Dictionary<short, string>();
foreach (var item in Enum.GetValues(typeof(FeedType)))
{
    feedTypeList.Add((short)item, Enum.GetName(typeof(FeedType), item));
}
ViewBag.FeedTypeList = new SelectList(feedTypeList, "Key", "Value", feed.FeedType);

In my View:

@Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList)
查看更多
甜甜的少女心
3楼-- · 2019-01-31 13:31

Enums are supported by the framework since MVC 5.1:

@Html.EnumDropDownListFor(m => m.Palette)

Displayed text can be customized:

public enum Palette
{
    [Display(Name = "Black & White")]
    BlackAndWhite,

    Colour
}

MSDN link: http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum

查看更多
唯我独甜
4楼-- · 2019-01-31 13:35

You can to this:

@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
查看更多
孤傲高冷的网名
5楼-- · 2019-01-31 13:35

The solution from PaulTheCyclist is spot on. But I wouldn't use RESX (I'd have to add a new .resx file for each new enum??)

Here is my HtmlHelper Expression:

public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TEnum>> expression, object attributes = null)
{
    //Get metadata from enum
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var enumType = GetNonNullableModelType(metadata);
    var values = Enum.GetValues(enumType).Cast<TEnum>();

    //Convert enumeration items into SelectListItems
    var items =
        from value in values
        select new SelectListItem
        {
            Text = value.ToDescription(),
            Value = value.ToString(),
            Selected = value.Equals(metadata.Model)
        };

    //Check for nullable value types
    if (metadata.IsNullableValueType)
    {
        var emptyItem = new List<SelectListItem>
        {
            new SelectListItem {Text = string.Empty, Value = string.Empty}
        };
        items = emptyItem.Concat(items);
    }

    //Return the regular DropDownlist helper
    return htmlHelper.DropDownListFor(expression, items, attributes);
}

Here is how I declare my enums:

[Flags]
public enum LoanApplicationType
{
    [Description("Undefined")]
    Undefined = 0,

    [Description("Personal Loan")]
    PersonalLoan = 1,

    [Description("Mortgage Loan")]
    MortgageLoan = 2,

    [Description("Vehicle Loan")]
    VehicleLoan = 4,

    [Description("Small Business")]
    SmallBusiness = 8,
}

And here is the call from a Razor View:

<div class="control-group span2">
    <div class="controls">
        @Html.EnumDropDownListFor(m => m.LoanType, new { @class = "span2" })
    </div>
</div>

Where @Model.LoanType is an model property of the LoanApplicationType type

UPDATE: Sorry, forgot to include code for the helper function ToDescription()

/// <summary>
/// Returns Description Attribute information for an Enum value
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToDescription(this Enum value)
{
    if (value == null)
    {
        return string.Empty;
    }
    var attributes = (DescriptionAttribute[]) value.GetType().GetField(
        Convert.ToString(value)).GetCustomAttributes(typeof (DescriptionAttribute), false);
    return attributes.Length > 0 ? attributes[0].Description : Convert.ToString(value);
}
查看更多
女痞
6楼-- · 2019-01-31 13:39

Extending the html helper to do it works well, but if you'd like to be able to change the text of the drop down values based on DisplayAttribute mappings, then you would need to modify it similar to this,

(Do this pre MVC 5.1, it's included in 5.1+)

public static IHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{
    var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
    var enumValues = Enum.GetValues(enumType).Cast<object>();
    var items = enumValues.Select(item =>
    {
        var type = item.GetType();
        var member = type.GetMember(item.ToString());
        var attribute = member[0].GetCustomAttribute<DisplayAttribute>();
        string text = attribute != null ? ((DisplayAttribute)attribute).Name : item.ToString();
        string value = ((int)item).ToString();
        bool selected = item.Equals(metadata.Model);
        return new SelectListItem
        {
            Text = text,
            Value = value,
            Selected = selected
        };
    });
    return html.DropDownListFor(expression, items, string.Empty, null);
}
查看更多
男人必须洒脱
7楼-- · 2019-01-31 13:43

Technically, you don't need a helper method, since Html.DropdownListFor only requires a SelectList or Ienumerable<SelectListItem>. You can just turn your enums into such an output and feed it in that way.

I use a static library method to convert enums into List<SelectListItem> with a few params/options:

public static List<SelectListItem> GetEnumsByType<T>(bool useFriendlyName = false, List<T> exclude = null,
    List<T> eachSelected = null, bool useIntValue = true) where T : struct, IConvertible
{
    var enumList = from enumItem in EnumUtil.GetEnumValuesFor<T>()
                    where (exclude == null || !exclude.Contains(enumItem))
                    select enumItem;

    var list = new List<SelectListItem>();

    foreach (var item in enumList)
    {
        var selItem = new SelectListItem();

        selItem.Text = (useFriendlyName) ? item.ToFriendlyString() : item.ToString();
        selItem.Value = (useIntValue) ? item.To<int>().ToString() : item.ToString();

        if (eachSelected != null && eachSelected.Contains(item))
            selItem.Selected = true;

        list.Add(selItem);
    }

    return list;
}

public static class EnumUtil
{
    public static IEnumerable<T> GetEnumValuesFor<T>()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }
    // other stuff in here too...
}


/// <summary>
/// Turns Camelcase or underscore separated phrases into properly spaces phrases
/// "DogWithMustard".ToFriendlyString() == "Dog With Mustard"
/// </summary>
public static string ToFriendlyString(this object o)
{
    var s = o.ToString();
    s = s.Replace("__", " / ").Replace("_", " ");

    char[] origArray = s.ToCharArray();
    List<char> newCharList = new List<char>();

    for (int i = 0; i < origArray.Count(); i++)
    {
        if (origArray[i].ToString() == origArray[i].ToString().ToUpper())
        {
            newCharList.Add(' ');
        }
        newCharList.Add(origArray[i]);
    }

    s = new string(newCharList.ToArray()).TrimStart();
    return s;
}

Your ViewModel can pass in the options you want. Here's a fairly complex one:

public IEnumerable<SelectListItem> PaymentMethodChoices 
{ 
    get 
    { 
        var exclusions = new List<Membership.Payment.PaymentMethod> { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal };
        var selected = new List<Membership.Payment.PaymentMethod> { this.SelectedPaymentMethod };
        return GetEnumsByType<Membership.Payment.PaymentMethod>(useFriendlyName: true, exclude: exclusions, eachSelected: selected); 
    }
}

So you wire your View's DropDownList against that IEnumerable<SelectListItem> property.

查看更多
登录 后发表回答