关于html:将枚举绑定到MVC 4中的DropDownList?

Binding an Enum to a DropDownList in MVC 4?

本问题已经有最佳答案,请猛点这里访问。

我一直在各地发现,将枚举绑定到下拉列表的常见方法是通过helper方法,对于这样一个看似简单的任务,helper方法似乎有点霸道。

在ASP.NET MVC 4中将枚举绑定到DropDownList的最佳方法是什么?


你可以这样做:

1
@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))


我认为这是唯一(干净)的方法,这是一个遗憾,但至少有几个选择。我建议你看看这个博客:http://paulthecyclist.com/2013/05/24/enum-dropdown/

抱歉,在这里复制太长,但要点是他为此创建了一个新的HTML助手方法。

所有源代码在GitHub上都可用。


自MVC 5.1以来,框架支持枚举:

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

可自定义显示的文本:

1
2
3
4
5
6
7
public enum Palette
{
    [Display(Name ="Black & White")]
    BlackAndWhite,

    Colour
}

msdn链接:http://www.asp.net/mvc/overview/releases/mvc51 release notes enum


在我的控制器中:

1
2
3
4
5
6
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);

在我看来:

1
@Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList)


从技术上讲,您不需要辅助方法,因为Html.DropdownListFor只需要SelectListIenumerable。您可以将枚举转换成这样的输出,然后以这种方式馈送它。

我使用静态库方法将枚举转换为List中的一些参数/选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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;
}

您的视图模型可以传递您想要的选项。这是一个相当复杂的问题:

1
2
3
4
5
6
7
8
9
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);
    }
}

因此,您将视图的DropDownList连接到Ienumerable属性。


保尔骑手的解决方案就在眼前。但是我不会使用resx(我必须为每个新枚举添加一个新的.resx文件??)

下面是我的htmlhelper表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
}

以下是我如何声明我的枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[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,
}

从剃刀的角度来看,这是一个要求:

1
        @Html.EnumDropDownListFor(m => m.LoanType, new { @class ="span2" })

其中,@Model.LoanType是LoanApplicationType类型的模型属性

更新:抱歉,忘记包含helper函数todescription()的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <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);
}


扩展HTML助手以使其正常工作,但是如果您希望能够基于DisplayAttribute映射更改下拉值的文本,则需要对此进行类似的修改,

(执行MVC 5.1之前的操作,它包含在5.1+中)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
}