asp.net - template - mvc dropdownlist enum




你如何從ASP.NET MVC中的枚舉創建一個下拉列表? (20)

我試圖使用Html.DropDownList擴展方法,但不知道如何使用它與枚舉。

比方說,我有這樣的枚舉:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

如何使用Html.DropDownList擴展方法來創建帶有這些值的下拉菜單?

或者,我最好只是簡單地創建一個for循環並手動創建Html元素?


對於MVC v5.1使用Html.EnumDropDownListFor

@Html.EnumDropDownListFor(
    x => x.YourEnumField,
    "Select My Type", 
    new { @class = "form-control" })

對於MVC v5使用EnumHelper

@Html.DropDownList("MyType", 
   EnumHelper.GetSelectList(typeof(MyType)) , 
   "Select My Type", 
   new { @class = "form-control" })

適用於MVC 5及更低版本

我把符文的答案翻譯成擴展方法:

namespace MyApp.Common
{
    public static class MyExtensions{
        public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        {
            var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                select new { Id = e, Name = e.ToString() };
            return new SelectList(values, "Id", "Name", enumObj);
        }
    }
}

這允許你寫:

ViewData["taskStatus"] = task.Status.ToSelectList();

通過using MyApp.Common


Html.DropDownListFor只需要IEnumerable,所以Prize的解決方案的替代方法如下。 這將允許你簡單地寫:

@Html.DropDownListFor(m => m.SelectedItemType, Model.SelectedItemType.ToSelectList())

[其中SelectedItemType是您的模型類型ItemTypes上的一個字段,並且您的模型非空]

另外,您並不需要泛化擴展方法,因為您可以使用enumValue.GetType()而不是typeof(T)。

編輯:這裡集成西蒙的解決方案,並包括ToDescription擴展方法。

public static class EnumExtensions
{
    public static IEnumerable<SelectListItem> ToSelectList(this Enum enumValue)
    {
        return from Enum e in Enum.GetValues(enumValue.GetType())
               select new SelectListItem
               {
                   Selected = e.Equals(enumValue),
                   Text = e.ToDescription(),
                   Value = e.ToString()
               };
    }

    public static string ToDescription(this Enum value)
    {
        var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
}

Here a Martin Faartoft variation where you can put custom labels which is nice for localization.

public static class EnumHtmlHelper
{
    public static SelectList ToSelectList<TEnum>(this TEnum enumObj, Dictionary<int, string> customLabels)
        where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                     select new { Id = e, Name = customLabels.First(x => x.Key == Convert.ToInt32(e)).Value.ToString() };

        return new SelectList(values, "Id", "Name", enumObj);
    }
}

Use in view:

@Html.DropDownListFor(m => m.Category, Model.Category.ToSelectList(new Dictionary<int, string>() { 
          { 1, ContactResStrings.FeedbackCategory }, 
          { 2, ContactResStrings.ComplainCategory }, 
          { 3, ContactResStrings.CommentCategory },
          { 4, ContactResStrings.OtherCategory }
      }), new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Category)

I ended up creating extention methods to do what is essentially the accept answer here. The last half of the Gist deals with Enum specifically.

https://gist.github.com/3813767


If you want to add localization support just change the s.toString() method to something like this:

ResourceManager rManager = new ResourceManager(typeof(Resources));
var dayTypes = from OperatorCalendarDay.OperatorDayType s in Enum.GetValues(typeof(OperatorCalendarDay.OperatorDayType))
               select new { ID = s, Name = rManager.GetString(s.ToString()) };

In here the typeof(Resources) is the resource you want to load, and then you get the localized String, also useful if your enumerator has values with multiple words.


This is my version of helper method. 我使用這個:

var values = from int e in Enum.GetValues(typeof(TEnum))
             select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };

Instead of that:

var values = from TEnum e in Enum.GetValues(typeof(TEnum))
           select new { ID = (int)Enum.Parse(typeof(TEnum),e.ToString())
                     , Name = e.ToString() };

這裡是:

public static SelectList ToSelectList<TEnum>(this TEnum self) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new ArgumentException("self must be enum", "self");
        }

        Type t = typeof(TEnum);

        var values = from int e in Enum.GetValues(typeof(TEnum))
                     select new { ID = e, Name = Enum.GetName(typeof(TEnum), e) };

        return new SelectList(values, "ID", "Name", self);
    }

一個超級簡單的方法來完成這件事 - 沒有看起來矯枉過正的所有擴展的東西是這樣的:

你的枚舉:

    public enum SelectedLevel
    {
       Level1,
       Level2,
       Level3,
       Level4
    }

控制器內部將Enum綁定到List:

    List<SelectedLevel> myLevels = Enum.GetValues(typeof(SelectedLevel)).Cast<SelectedLevel>().ToList();

之後,把它扔進ViewBag:

    ViewBag.RequiredLevel = new SelectList(myLevels);

最後只需將其綁定到視圖:

    @Html.DropDownList("selectedLevel", (SelectList)ViewBag.RequiredLevel, new { @class = "form-control" })

這是我發現的最簡單的方法,不需要任何擴展或任何瘋狂的東西。

更新 :請參閱下面的安卓評論。



http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum ,他們添加了EnumDropDownListFor()助手,因此不需要自定義擴展:

型號

public enum MyEnum
{
    [Display(Name = "First Value - desc..")]
    FirstValue,
    [Display(Name = "Second Value - desc...")]
    SecondValue
}

查看

@Html.EnumDropDownListFor(model => model.MyEnum)

使用標籤助手(ASP.NET MVC 6)

<select asp-for="@Model.SelectedValue" asp-items="Html.GetEnumSelectList<MyEnum>()">

基於Simon的回答,類似的方法是從資源文件中獲取Enum值,而不是Enum本身中的描述屬性。 如果您的站點需要使用多種語言進行渲染,並且如果要為Enums指定特定的資源文件,那麼這很有幫助,您可以更進一步,並在Enum中添加Enum值,並通過擴展名引用它們像[EnumName] _ [EnumValue]這樣的約定 - 最終減少了輸入!

該擴展然後看起來像:

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 = from enumValue in enumValues                        
                select new SelectListItem
                {
                    Text = GetResourceValueForEnumValue(enumValue),
                    Value = ((int)enumValue).ToString(),
                    Selected = enumValue.Equals(metadata.Model)
                };


    return html.DropDownListFor(expression, items, string.Empty, null);
}

private static string GetResourceValueForEnumValue<TEnum>(TEnum enumValue)
{
    var key = string.Format("{0}_{1}", enumValue.GetType().Name, enumValue);

    return Enums.ResourceManager.GetString(key) ?? enumValue.ToString();
}

Enums.Resx文件中的資源看起來像ItemTypes_Movie:Film

我喜歡做的另一件事是,我不想直接調用擴展方法,而是使用@ Html.EditorFor(x => x.MyProperty)來調用它,或者理想情況下只需將整個表單放在一個整齊的@ Html.EditorForModel()。 為此,我將字符串模板更改為如下所示

@using MVCProject.Extensions

@{
    var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;

    @(typeof (Enum).IsAssignableFrom(type) ? Html.EnumDropDownListFor(x => x) : Html.TextBoxFor(x => x))
}

如果您對此感興趣,我已經在我的博客上提供了更詳細的答案:

http://paulthecyclist.com/2013/05/24/enum-dropdown/


我已經完成了以下工作並成功完成:

  • 在view.cshtml中:

@model MyModel.cs

@Html.EnumDropDownListFor(m=>m.MyItemType )
  • 在Model:MyModel.cs中

public ItemTypes MyItemType { get; set; }


我找到的最佳解決方案是將此博客與Simon Goldstone的答案結合起來。

這允許在模型中使用枚舉。 基本上這個想法是使用整數屬性以及枚舉,並模擬整數屬性。

然後使用[System.ComponentModel.Description]屬性為顯示文本註釋模型,並在視圖中使用“EnumDropDownListFor”擴展名。

這使得視圖和模型非常易讀易維護。

模型:

public enum YesPartialNoEnum
{
    [Description("Yes")]
    Yes,
    [Description("Still undecided")]
    Partial,
    [Description("No")]
    No
}

//........

[Display(Name = "The label for my dropdown list")]
public virtual Nullable<YesPartialNoEnum> CuriousQuestion{ get; set; }
public virtual Nullable<int> CuriousQuestionId
{
    get { return (Nullable<int>)CuriousQuestion; }
    set { CuriousQuestion = (Nullable<YesPartialNoEnum>)value; }
}

視圖:

@using MyProject.Extensions
{
//...
    @Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}

擴展(直接來自Simon Goldstone的答案 ,包括在內以便完整):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;

namespace MyProject.Extensions
{
    //Extension methods must be defined in a static class
    public static class MvcExtensions
    {
        private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
        {
            Type realModelType = modelMetadata.ModelType;

            Type underlyingType = Nullable.GetUnderlyingType(realModelType);
            if (underlyingType != null)
            {
                realModelType = underlyingType;
            }
            return realModelType;
        }

        private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };

        public static string GetEnumDescription<TEnum>(TEnum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());

            DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if ((attributes != null) && (attributes.Length > 0))
                return attributes[0].Description;
            else
                return value.ToString();
        }

        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
        {
            return EnumDropDownListFor(htmlHelper, expression, null);
        }

        public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            Type enumType = GetNonNullableModelType(metadata);
            IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();

            IEnumerable<SelectListItem> items = from value in values
                                                select new SelectListItem
                                                {
                                                    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)
                items = SingleEmptyItem.Concat(items);

            return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
        }
    }
}

我遇到了同樣的問題,發現了這個問題,並認為Ash提供的解決方案不是我想要的; 與內置的Html.DropDownList()函數相比,自己創建HTML意味著更少的靈活性。

原來C#3等使得這非常容易。 我有一個名為TaskStatusenum

var statuses = from TaskStatus s in Enum.GetValues(typeof(TaskStatus))
               select new { ID = s, Name = s.ToString() };
ViewData["taskStatus"] = new SelectList(statuses, "ID", "Name", task.Status);

這創建了一個很好的SelectList ,可以像您在視圖中習慣的那樣使用它:

<td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr>

匿名類型和LINQ使這更加優雅恕我直言。 Ash沒有任何意圖。 :)


所以沒有擴展功能,如果你正在尋找簡單和容易..這就是我所做的

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

其中XXXXX.Sites.YYYY.Models.State是一個枚舉

可能更好地做輔助功能,但當時間很短時,這將完成工作。


此擴展方法的另一個修復 - 當前版本不選擇枚舉的當前值。 我修正了最後一行:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                       select new
                       {
                           ID = (int)Enum.Parse(typeof(TEnum), e.ToString()),
                           Name = e.ToString()
                       };


        return new SelectList(values, "ID", "Name", ((int)Enum.Parse(typeof(TEnum), enumObj.ToString())).ToString());
    }


這是一個更好的封裝解決方案:

http://www.spicelogic.com/Journal/ASP-NET-MVC-DropDownListFor-Html-Helper-Enum-5

說這裡是你的模型:

樣本用法:

生成的用戶界面:

並生成HTML

助手擴展源代碼快照:

您可以從我提供的鏈接下載示例項目。

編輯:這是代碼:

public static class EnumEditorHtmlHelper
{
    /// <summary>
    /// Creates the DropDown List (HTML Select Element) from LINQ 
    /// Expression where the expression returns an Enum type.
    /// </summary>
    /// <typeparam name="TModel">The type of the model.</typeparam>
    /// <typeparam name="TProperty">The type of the property.</typeparam>
    /// <param name="htmlHelper">The HTML helper.</param>
    /// <param name="expression">The expression.</param>
    /// <returns></returns>
    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression) 
        where TModel : class
    {
        TProperty value = htmlHelper.ViewData.Model == null 
            ? default(TProperty) 
            : expression.Compile()(htmlHelper.ViewData.Model);
        string selected = value == null ? String.Empty : value.ToString();
        return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected));
    }

    /// <summary>
    /// Creates the select list.
    /// </summary>
    /// <param name="enumType">Type of the enum.</param>
    /// <param name="selectedItem">The selected item.</param>
    /// <returns></returns>
    private static IEnumerable<SelectListItem> createSelectList(Type enumType, string selectedItem)
    {
        return (from object item in Enum.GetValues(enumType)
                let fi = enumType.GetField(item.ToString())
                let attribute = fi.GetCustomAttributes(typeof (DescriptionAttribute), true).FirstOrDefault()
                let title = attribute == null ? item.ToString() : ((DescriptionAttribute) attribute).Description
                select new SelectListItem
                  {
                      Value = item.ToString(), 
                      Text = title, 
                      Selected = selectedItem == item.ToString()
                  }).ToList();
    }
}

這是符文和獎的答案改變為使用Enum int值作為ID。

樣本枚舉:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

擴展方法:

    public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
    {
        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                     select new { Id = (int)Enum.Parse(typeof(TEnum), e.ToString()), Name = e.ToString() };

        return new SelectList(values, "Id", "Name", (int)Enum.Parse(typeof(TEnum), enumObj.ToString()));
    }

使用示例:

 <%=  Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>

請記住導入包含擴展方法的名稱空間

<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>

生成的HTML示例:

<select id="MyEnumList" name="MyEnumList">
    <option value="1">Movie</option>
    <option selected="selected" value="2">Game</option>
    <option value="3">Book </option>
</select>

請注意,用來調用ToSelectList的項目是選定的項目。


@Html.DropDownListFor(model => model.MaritalStatus, new List<SelectListItem> 
{  

new SelectListItem { Text = "----Select----", Value = "-1" },


new SelectListItem { Text = "Marrid", Value = "M" },


 new SelectListItem { Text = "Single", Value = "S" }

})

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




asp.net-mvc