How do you create a dropdownlist from an enum in ASP.NET MVC?

后端 未结 30 1908
不知归路
不知归路 2020-11-21 16:36

I\'m trying to use the Html.DropDownList extension method but can\'t figure out how to use it with an enumeration.

Let\'s say I have an enumeration like

相关标签:
30条回答
  • 2020-11-21 16:41

    Well I'm really late to the party, but for what it is worth, I have blogged about this very subject whereby I create a EnumHelper class that enables very easy transformation.

    http://jnye.co/Posts/4/creating-a-dropdown-list-from-an-enum-in-mvc-and-c%23

    In your controller:

    //If you don't have an enum value use the type
    ViewBag.DropDownList = EnumHelper.SelectListFor<MyEnum>();
    
    //If you do have an enum value use the value (the value will be marked as selected)    
    ViewBag.DropDownList = EnumHelper.SelectListFor(MyEnum.MyEnumValue);
    

    In your View:

    @Html.DropDownList("DropDownList")
    @* OR *@
    @Html.DropDownListFor(m => m.Property, ViewBag.DropDownList as SelectList, null)
    

    The helper class:

    public static class EnumHelper
    {
        // Get the value of the description attribute if the   
        // enum has one, otherwise use the value.  
        public static string GetDescription<TEnum>(this TEnum value)
        {
            var fi = value.GetType().GetField(value.ToString());
    
            if (fi != null)
            {
                var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    
                if (attributes.Length > 0)
                {
                    return attributes[0].Description;
                }
            }
    
            return value.ToString();
        }
    
        /// <summary>
        /// Build a select list for an enum
        /// </summary>
        public static SelectList SelectListFor<T>() where T : struct
        {
            Type t = typeof(T);
            return !t.IsEnum ? null
                             : new SelectList(BuildSelectListItems(t), "Value", "Text");
        }
    
        /// <summary>
        /// Build a select list for an enum with a particular value selected 
        /// </summary>
        public static SelectList SelectListFor<T>(T selected) where T : struct
        {
            Type t = typeof(T);
            return !t.IsEnum ? null
                             : new SelectList(BuildSelectListItems(t), "Text", "Value", selected.ToString());
        }
    
        private static IEnumerable<SelectListItem> BuildSelectListItems(Type t)
        {
            return Enum.GetValues(t)
                       .Cast<Enum>()
                       .Select(e => new SelectListItem { Value = e.ToString(), Text = e.GetDescription() });
        }
    }
    
    0 讨论(0)
  • 2020-11-21 16:43

    I would like to answer this question in a different way where, user need not to do anything in controller or Linq expression. This way...

    I have a ENUM

    public enum AccessLevelEnum
        {
            /// <summary>
            /// The user cannot access
            /// </summary>
            [EnumMember, Description("No Access")]
            NoAccess = 0x0,
    
            /// <summary>
            /// The user can read the entire record in question
            /// </summary>
            [EnumMember, Description("Read Only")]
            ReadOnly = 0x01,
    
            /// <summary>
            /// The user can read or write
            /// </summary>
            [EnumMember, Description("Read / Modify")]
            ReadModify = 0x02,
    
            /// <summary>
            /// User can create new records, modify and read existing ones
            /// </summary>
            [EnumMember, Description("Create / Read / Modify")]
            CreateReadModify = 0x04,
    
            /// <summary>
            /// User can read, write, or delete
            /// </summary>
            [EnumMember, Description("Create / Read / Modify / Delete")]
            CreateReadModifyDelete = 0x08,
    
            /*/// <summary>
            /// User can read, write, or delete
            /// </summary>
            [EnumMember, Description("Create / Read / Modify / Delete / Verify / Edit Capture Value")]
            CreateReadModifyDeleteVerify = 0x16*/
        }
    

    Now I canto simply create a dropdown by using this enum.

    @Html.DropDownList("accessLevel",new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class = "form-control" })
    

    OR

    @Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum))),new { @class = "form-control" })
    

    If you want to make a index selected then try this

    @Html.DropDownListFor(m=>m.accessLevel,new SelectList(AccessLevelEnum.GetValues(typeof(AccessLevelEnum)) , AccessLevelEnum.NoAccess ),new { @class = "form-control" })
    

    Here I have used AccessLevelEnum.NoAccess as an extra parameter for default selecting the dropdown.

    0 讨论(0)
  • 2020-11-21 16:45

    So without Extension functions if you are looking for simple and easy.. This is what I did

    <%= Html.DropDownListFor(x => x.CurrentAddress.State, new SelectList(Enum.GetValues(typeof(XXXXX.Sites.YYYY.Models.State))))%>
    

    where XXXXX.Sites.YYYY.Models.State is an enum

    Probably better to do helper function, but when time is short this will get the job done.

    0 讨论(0)
  • 2020-11-21 16:46

    @Simon Goldstone: Thanks for your solution, it can be perfectly applied in my case. The only problem is I had to translate it to VB. But now it is done and to save other people's time (in case they need it) I put it here:

    Imports System.Runtime.CompilerServices
    Imports System.ComponentModel
    Imports System.Linq.Expressions
    
    Public Module HtmlHelpers
        Private Function GetNonNullableModelType(modelMetadata As ModelMetadata) As Type
            Dim realModelType = modelMetadata.ModelType
    
            Dim underlyingType = Nullable.GetUnderlyingType(realModelType)
    
            If Not underlyingType Is Nothing Then
                realModelType = underlyingType
            End If
    
            Return realModelType
        End Function
    
        Private ReadOnly SingleEmptyItem() As SelectListItem = {New SelectListItem() With {.Text = "", .Value = ""}}
    
        Private Function GetEnumDescription(Of TEnum)(value As TEnum) As String
            Dim fi = value.GetType().GetField(value.ToString())
    
            Dim attributes = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
    
            If Not attributes Is Nothing AndAlso attributes.Length > 0 Then
                Return attributes(0).Description
            Else
                Return value.ToString()
            End If
        End Function
    
        <Extension()>
        Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum))) As MvcHtmlString
            Return EnumDropDownListFor(htmlHelper, expression, Nothing)
        End Function
    
        <Extension()>
        Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum)), htmlAttributes As Object) As MvcHtmlString
            Dim metaData As ModelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
            Dim enumType As Type = GetNonNullableModelType(metaData)
            Dim values As IEnumerable(Of TEnum) = [Enum].GetValues(enumType).Cast(Of TEnum)()
    
            Dim items As IEnumerable(Of SelectListItem) = From value In values
                Select New SelectListItem With
                {
                    .Text = GetEnumDescription(value),
                    .Value = value.ToString(),
                    .Selected = value.Equals(metaData.Model)
                }
    
            ' If the enum is nullable, add an 'empty' item to the collection
            If metaData.IsNullableValueType Then
                items = SingleEmptyItem.Concat(items)
            End If
    
            Return htmlHelper.DropDownListFor(expression, items, htmlAttributes)
        End Function
    End Module
    

    End You use it like this:

    @Html.EnumDropDownListFor(Function(model) (model.EnumField))
    
    0 讨论(0)
  • 2020-11-21 16:52

    Now this feature is supported out-of-the-box in MVC 5.1 through @Html.EnumDropDownListFor()

    Check the following link:

    https://docs.microsoft.com/en-us/aspnet/mvc/overview/releases/mvc51-release-notes#Enum

    It is really shame that it took Microsoft 5 years to implement such as feature which is so in demand according to the voting above!

    0 讨论(0)
  • 2020-11-21 16:54

    Expanding on Prise and Rune's answers, if you'd like to have the value attribute of your select list items map to the integer value of the Enumeration type, rather than the string value, use the following code:

    public static SelectList ToSelectList<T, TU>(T enumObj) 
        where T : struct
        where TU : struct
    {
        if(!typeof(T).IsEnum) throw new ArgumentException("Enum is required.", "enumObj");
    
        var values = from T e in Enum.GetValues(typeof(T))
                     select new { 
                        Value = (TU)Convert.ChangeType(e, typeof(TU)),
                        Text = e.ToString() 
                     };
    
        return new SelectList(values, "Value", "Text", enumObj);
    }
    

    Instead of treating each Enumeration value as a TEnum object, we can treat it as a object and then cast it to integer to get the unboxed value.

    Note: I also added a generic type constraint to restrict the types for which this extension is available to only structs (Enum's base type), and a run-time type validation which ensures that the struct passed in is indeed an Enum.

    Update 10/23/12: Added generic type parameter for underlying type and fixed non-compilation issue affecting .NET 4+.

    0 讨论(0)
提交回复
热议问题