ASP.NET MVC의 열거 형에서 드롭 다운 목록을 어떻게 만듭니 까?


670

Html.DropDownList확장 방법 을 사용하려고하는데 열거 형과 함께 사용하는 방법을 알 수 없습니다.

다음과 같은 열거 형이 있다고 가정 해 봅시다.

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

Html.DropDownList확장 방법을 사용하여 이러한 값으로 드롭 다운을 만드는 방법은 무엇입니까?

아니면 단순히 for 루프를 만들고 Html 요소를 수동으로 만드는 것이 가장 좋은 방법입니까?

답변:


841

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 이하

Rune의 답변을 확장 방법으로 굴 렸습니다.

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


13
나는 그것을 작동시킬 수 없었다, 당신은 도와주세요. 내가 Post.PostType.ToSelectList ()를 할 때; 확장명을 인식하지 못합니까?
Barbaros Alp

3
나는 이것도 작동시키지 못했습니다. 작업 클래스에서 Status가 Enum 속성입니까? 이것은 열거 된 값 중 하나입니까?
Daryl

9
여기서 T : struct, IConvertible을 참조하십시오. stackoverflow.com/questions/79126/…
Richard Garside

8
이것은 멋지다. 누군가가 구현에 어려움을 겪고 있다면 여기에 내가 한 일이 있습니다. HtmlHelpers 폴더에 EnumHelpers 클래스를 추가했습니다. 위의 코드를 사용했습니다. @TodK 권장 사항에 따라 네임 스페이스를 추가했습니다 : <add namespace = "xxx.HtmlHelpers"/>. 그리고 나는 그런 같은 면도기 페이지에서 그것을 사용 : @ Html.DropDownListFor (모델 => model.Status, @ Model.Status.ToSelectList ()) HTH
제프 보든

6
최신 ASP.NET MVC에는 기본 방법이 있습니다. stackoverflow.com/a/22295360/1361084
Ofiris

359

나는 이것에 대해 파티에 늦었다는 것을 알고 있지만,이 변형은 드롭 다운에서 열거 상수 대신 설명 문자열을 사용할 수 있기 때문에이 변형이 유용하다고 생각했습니다. 이렇게하려면 각 열거 항목을 [System.ComponentModel.Description] 특성으로 장식하십시오.

예를 들면 다음과 같습니다.

public enum TestEnum
{
  [Description("Full test")]
  FullTest,

  [Description("Incomplete or partial test")]
  PartialTest,

  [Description("No test performed")]
  None
}

내 코드는 다음과 같습니다.

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

 ...

 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);
    }

그런 다음보기 에서이 작업을 수행 할 수 있습니다.

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

이것이 당신에게 도움이되기를 바랍니다!

** 편집 2014-JAN-23 : Microsoft는 이제 EnumDropDownListFor 기능이있는 MVC 5.1을 출시했습니다. 슬프게도 [Description] 속성을 준수하지 않는 것 같으므로 위의 코드는 여전히 유효 합니다. MVC 5.1에 대한 Microsoft 릴리스 정보의 Enum 섹션을 참조 하십시오.

업데이트 : Display 속성을 지원 [Display(Name = "Sample")]하므로 사용할 수 있습니다.

[업데이트-방금 확인한 코드는 다음 코드의 확장 된 버전입니다. https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- dropdownlist-helper-for-enums / , 몇 가지 추가 사항이 있습니다. 그렇다면 기여는 공평 해 보일 것입니다 ;-)]


28
+1 여기에 모든 답변 중 가장 유용한 것으로 나타났습니다. 나는 이것을 재사용 성이 높은 코드로 바꿀 수 있었다. 감사합니다!
Ed Charbeneau

43
Visual Studio에는 이상한 버그가 있습니다. 참조하지 않으면 찾을 수 없다고 System.Web.Mvc.Html말하지만 DropDownListFor해결할 수는 없습니다. 수동으로해야 using System.Web.Mvc.Html;합니다. 그냥 알아
Kezzer


1
당신이 GetEnumDescription의 결과를 캐시 할 수 있다면 훌륭한 솔루션 덕분에, 더 나은 것
M. Mennan 카라

17
새로운 MVC 5.1 EnumDropDownListFor는 [Description ( "")]을 사용하지 않지만 [Display (Name = "")]를 사용합니다! 즐기십시오 :)
Supergibbs

195

에서 ASP.NET MVC 5.1 , 그들은 추가 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>()">

21
이것은 어떻게 든 첫 번째 장소로 올라갈 필요가있다

3
MVC 5.1과 관련된 새 질문을 작성하여 답변으로 작성한 다음 게시물에 대한 링크를 보내서 내가 좋아하는 것을 찬양 할 수 있도록해야합니다.
Kevin Heidt

2
EnumDropDownListFor ()에 대해 마음에 들지 않는 점은 텍스트가 아닌 열거 형의 int 값을 DB에 저장한다는 것입니다. 따라서 새 열거 형 항목을 추가하기로 선택한 경우 반드시 목록의 끝 부분에 있어야합니다 저장된 데이터베이스 int 값과 열거 형 항목의 원래 위치 간의 관계를 잃지 않도록합니다. 텍스트가 저장되는 경우 불필요한 제한입니다. 또한, 나는 다른 곳에서 텍스트 값을 찾아야하는 정수 대신 db를보고 텍스트를 볼 수 있습니다. 그렇지 않으면이 HTML 도우미가 사용하기가 매우 편리합니다.
Giovanni

2
@ Giovanni-당신은 당신의 자신의 숫자 값을 지정할 수 있습니다.
Tommy

1
@Giovanni Strict 디자인은 각 열거 항목에 값을 할당해야합니다 (중요한 경우). int 값을 저장하면 스토리지를 절약하고 성능을 향상시킬 때 (일부 검색을 수행 할 때) 더 좋습니다.
킹 킹

130

나는 같은 문제에 부딪 쳤고,이 질문을 발견했으며, Ash가 제공 한 솔루션이 내가 찾고있는 솔루션이 아니라고 생각했다. HTML을 직접 만들어야한다는 것은 내장 Html.DropDownList()함수에 비해 유연성이 떨어집니다 .

C # 3 등이 매우 쉽습니다. 나는 enum전화했다 TaskStatus:

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보기에서 익숙한 것처럼 사용할 수 있는 좋은 ol ' 을 만듭니다 .

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

익명 유형과 LINQ는 이것을 훨씬 더 우아하게 만듭니다. 범죄 의도가 없습니다, 애쉬 :)


좋은 대답입니다! 나는 누군가 linq와 SelectList를 사용하기를 바랐다. :) 기쁘다.
Pure.Krome

1
ID = s 값이 아닌 DataTextField를 제공합니까? 이유가 무엇입니까? 감사합니다
Barbaros Alp

1
룬, 나는이 동일한 방법을 사용했으며 DropDownList는 서버에 게시 할 때 렌더링을 수행했지만 선택한 값을 저장하지 않습니다.
clockwiseq

5
@BarbarosAlp ID가 숫자가 되려면 열거를 int로 캐스팅해야합니다.select new { ID = (int)s, Name = s.ToString() };
Keith

이것은 그 단순성 때문에 내가 가장 좋아하는 대답입니다. 선택한 답변에 솔루션이 사용되었으므로 크레딧이 충분하지 않습니다.
anar khalilov

63

더 나은 캡슐화 솔루션은 다음과 같습니다.

https://www.spicelogic.com/Blog/enum-dropdownlistfor-asp-net-mvc-5

모델이 여기 있다고 가정하십시오.

여기에 이미지 설명을 입력하십시오

샘플 사용법 :

여기에 이미지 설명을 입력하십시오

생성 된 UI : 여기에 이미지 설명을 입력하십시오

그리고 생성 된 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();
    }
}

2
단지 내 의견이지만,이 답변은 허용되는 답변보다 훨씬 깨끗하다고 ​​생각합니다. 특히 Description 특성을 사용하는 옵션이 마음에 듭니다. 사람들이 다운로드하지 않고 복사 / 붙여 넣을 수 있도록 코드를 추가했습니다.
벤 밀스

확장 메서드를 DropDownListFor 대신 EnumDropDownListFor로 호출하십시오. 사용법 :-> @ Html.EnumDropDownListFor (x => x.Gender)
sandeep talabathula

"선택하십시오"요소를 하나 더 추가하려는 사용자의 경우 return htmlHelper.DropDownListFor (expression, createSelectList (expression.ReturnType, selected, firstElement), "Please Select");
Sandeep

1
잘 작동합니다! 그러나 세부 정보 페이지에서 DisplayFor ()는 해당 설명 대신 열거의 선택된 값을 표시합니다. 나는 이것이 열거 형에 대해 DisplayFor ()에 대한 과부하를 요구한다고 가정합니다. 아무도 이것에 대한 해결책이 있습니까?
corix010

48

Html.DropDownList의 경우 IEnumerable 만 필요하므로 Prise 솔루션의 대안은 다음과 같습니다. 이를 통해 간단하게 작성할 수 있습니다.

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

[SelectedItemType이 ItemTypes 유형의 모델에 대한 필드이고 모델이 null이 아닌 경우]

또한 typeof (T) 대신 enumValue.GetType ()을 사용할 수 있으므로 확장 메서드를 실제로 일반화 할 필요는 없습니다.

편집 : 여기에 Simon의 솔루션도 통합되었으며 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();
    }
}

나를 위해 작동하지 않습니다 ( 'System.NullReferenceException : 객체 참조가 객체의 인스턴스로 설정되지 않았습니다.') ... 내 '모델'이 null입니다 ... Simon이 가지고있는 'GetNonNullableModelType'과 관련이 있습니다. 포함
Learner

@Cristi, 당신은 맞습니다.이 솔루션은 모델이 null 인 조건에서 사용되도록 의도되지 않았습니다. 나는 일반적으로 그러한 디자인을 피하고 "빈"모델로 초기화하려고합니다.
Zaid Masud

글쎄, asp mvc를 처음 사용하지만 .Net에 꽤 경험이 있습니다. 감사합니다, 당신이 제안한 것을 살펴볼 것입니다. 귀하의 ToDescription 확장 프로그램이 'Enum'범위를 벗어났습니다. 나는 '객체'자체에 잘 어울린다고 생각합니다. 이것이 내가 Simon의 코드를 가져 와서 조금 더 정리했을 때 사용한 것입니다.
Learner

@Cristi "Enum"범위를 벗어난 것의 의미를 이해하기는 어렵지만 ToDescription 확장 방법이 ItemTypes 열거 형에 강력하게 입력되지 않았다고 말하는 것 같습니다. 이것은 의도적이며 모든 enum에서 확장 메서드를 일반적으로 사용할 수있게합니다. 일반적인 확장 방법과 비교하면 각 방법의 장단점이 있습니다. 특히, 당신이 계산하면 열거 형에만 구속 할 수 없습니다.
Zaid Masud

1
감사합니다. 설명이없는 경우 확장 FromCamelCase를 사용하도록 value.ToString을 변경했습니다. 그것이 내가 롤하는 방법입니다 :)
Valamas

33

간단하고 쉬운 방법을 찾고 있다면 확장 기능이 없으면 .. 이것이 내가 한 일입니다.

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

여기서 XXXXX.Sites.YYYY.Models.State는 열거 형입니다.

아마도 도우미 기능을 수행하는 것이 좋을지 모르지만 시간이 짧으면 작업이 완료됩니다.


이것은 드롭 다운을 채우는 것이 좋지만 Html.DropDownListFor에 대한 면도기 구문에서 기본 선택된 값을 어떻게 설정합니까? 열거 형 콤보 상자가있는 테이블을 표시하고 이전 값에 따라 선택한 값을 설정해야합니다.
Johncl

2
선택된 값을 가진 두 번째 매개 변수를 새로운 SelectList (IEnumerable, object) 함수에 전달할 수 있어야합니다. MSDN Dococumentation : msdn.microsoft.com/en-us/library/dd460123.aspx
Marty Trenouth

23

선택 목록 항목의 값 속성이 문자열 값이 아닌 열거 유형의 정수 값에 맵핑되도록하려면 Prize 및 Rune의 답변을 확장하십시오. 다음 코드를 사용하십시오.

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);
}

각 열거 형 값을 TEnum 객체로 취급하는 대신이를 객체로 취급 한 다음 정수로 변환하여 상자에 넣지 않은 값을 얻을 수 있습니다.

노트 : 또한이 확장을 사용할 수있는 유형을 구조체 (Enum의 기본 유형)로 제한하는 일반 유형 제약 조건과 전달 된 구조체가 실제로 Enum인지 확인하는 런타임 유형 유효성 검사를 추가했습니다.

업데이트 10/23/12 : 기본 형식에 대한 일반 형식 매개 변수가 추가 되었으며 .NET 4+에 영향을주는 비 컴파일 문제가 해결되었습니다.


감사! 이것이 내가 필요한 대답이었습니다. Enum의 정수 값을 데이터베이스에 열로 저장하고 있으며이 솔루션이 완벽하게 작동하는 것 같습니다.
grimus

그러나 int가 아닌 char을 저장하면 어떻게됩니까? 내 사건이야 분명히 나는 ​​(int)를 (char)로 바꿀 수 있지만이 일반적인 것을 만드는 것은 어떻습니까. 그렇게하는 방법?
Stefanvds

@Stefandvds 이것은 올바른 표현 형식으로 캐스팅하는 것과 관련하여 훌륭한 질문입니다. 방금 수행 한 테스트를 기반으로 실제 유형을 다른 유형 매개 변수로 지정하는 것이 유일한 방법으로 보입니다. ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... }
Nathan Taylor


열거 형의 값이 int이면 간단히 사용할 수 있습니다 Value = Convert.ToInt32(e). (int)e컴파일하지 않습니다. :(
Andrew

11

Prise의 확장 방법을 사용하여 텍스트 대신 숫자를 얻는 문제를 해결합니다.

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", enumObj);
}

그것이 내가 생각했던 것보다 더 추악하지만, 그것이 내가 찾던 것입니다. Visual Studio에서 왜 직접 캐스트 e할 수 없는지 궁금 합니다 int.
Andrew

또는 간단하게 사용할 수 있습니다 ID = Convert.ToInt32(e).
앤드류

11

이 작업을 수행하는 매우 쉬운 방법-과도한 확장 기능을 사용하지 않으면 다음과 같습니다.

당신의 열거 :

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

컨트롤러 내부에서 Enum을 목록에 바인딩합니다.

    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" })

이것은 내가 찾은 가장 쉬운 방법이며 확장 기능이나 그 어떤 것도 필요하지 않습니다.

업데이트 : 아래 Andrews 의견을 참조하십시오.


3
열거 형에 값을 할당하지 않은 경우에만 작동합니다. 이있는 경우 Level1 = 1드롭 다운 값은 "Level1"대신 사용됩니다 1.
앤드류

11

내가 찾은 최고의 솔루션은 이 블로그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);
        }
    }
}

MVC 4 면도기는 작동하지 않습니다. 보기 또는 런타임에서 error = "다음 메소드 또는 속성 'LDN.Extensions.MvcExtensions.EnumDropDownListFor <MyModel, LDN.Models.YesPartialNoEnum?> (System.Web.Mvc.HtmlHelper <MyModel>, 시스템간에 호출이 모호합니다. .Linq.Expressions.Expression <System.Func <MyModel, LDN.Models.YesPartialNoEnum? >>) 'and .... "그리고 동일한 소품이 다시 반복되는 동일한 동일한 메소드 (여기에 충분한 문자가 허용되지 않음).
Marc


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

좋은! 이런 식으로 열거 형에서 가치와 텍스트를 얻는 방법은 무엇입니까? 나는 SomeEnum {some1 = 1, some2 = 2}를 가지고 있음을 의미합니다. 선택 목록의 텍스트에 대한 값 (1, 2)과 텍스트 (some1, some2)를
가져와야합니다.

7

Enum을 사용하도록 변경된 Rune & Prize 답변입니다. int 아이디로 값입니다.

샘플 열거 형 :

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()) %>

Extension 메서드가 포함 된 네임 스페이스를 가져와야합니다.

<%@ 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선택한 항목입니다.


또는 간단하게 사용할 수 있습니다 Id = Convert.ToInt32(e).
Andrew

6

이 Razor 버전입니다 :

@{
    var itemTypesList = new List<SelectListItem>();
    itemTypesList.AddRange(Enum.GetValues(typeof(ItemTypes)).Cast<ItemTypes>().Select(
                (item, index) => new SelectListItem
                {
                    Text = item.ToString(),
                    Value = (index).ToString(),
                    Selected = Model.ItemTypeId == index
                }).ToList());
 }


@Html.DropDownList("ItemTypeId", itemTypesList)

열거 형이 0으로 시작하는 연속 값으로 구성된 경우에만 작동합니다. 플래그 열거 형은이 기능을 수행하지 않습니다. 그러나 인덱싱 된 Select를 창의적으로 사용합니다.
Suncat2000

6

.NET 핵심에서 당신은이를 사용할 수 있습니다 :

@Html.DropDownListFor(x => x.Foo, Html.GetEnumSelectList<MyEnum>())

1
또는 태그 도우미를 사용하십시오 <select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList<MyEnum>()"></select>.
파스칼 R.

그래, Id는 형식이 순수한 HTML에 가까울수록 태그 헬퍼가 더 좋다고 말합니다.)
GoldenAge

@ Html.DropDownListFor (x => x.Foo, Html.GetEnumSelectList (typeof (FooEnum)))
Fereydoon Barikzehy


5

Simon의 답변을 바탕으로 Enum 자체의 설명 속성 대신 리소스 파일에서 Enum 값을 표시하는 비슷한 방법이 있습니다. 이는 사이트를 여러 언어로 렌더링해야하는 경우에 유용하며 Enum에 대한 특정 리소스 파일을 가지고 있다면 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처럼 보이는 : 필름

내가하고 싶은 또 다른 일은 확장 메서드를 직접 호출하는 대신 @ 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/


5

글쎄, 난 정말 파티에 늦었지만, 그만한 가치가 있기 때문에 나는이 주제에 대해 블로그를 만들었습니다. EnumHelper 매우 쉬운 변형을 가능하게 클래스를 .

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

컨트롤러에서 :

//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);

당신의보기에서 :

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

도우미 클래스 :

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() });
    }
}

4

나는 이것에 매우 늦었지만, 한 줄의 코드 로이 작업을 수행하는 정말 멋진 방법을 찾았습니다 .Unstrained Melody NuGet 패키지 (Jon Skeet의 멋진 작은 라이브러리) 를 추가하면 행복합니다 .

이 솔루션은 다음과 같은 이유로 더 좋습니다.

  1. (일반 유형 제약 조건으로) 값이 실제로 열거 형 값인지 확인합니다 (제한되지 않은 멜로디로 인해)
  2. 불필요 한 멜로디로 인해 불필요한 권투를 피합니다.
  3. 모든 설명에서 캐시를 사용하지 않도록 모든 설명을 캐시합니다 (제한되지 않은 멜로디로 인해)
  4. 다른 솔루션보다 코드가 적습니다!

이 작업을 수행하는 단계는 다음과 같습니다.

  1. 패키지 관리자 콘솔에서 "Install-Package UnconstrainedMelody"
  2. 다음과 같이 모델에 속성을 추가하십시오.

    //Replace "YourEnum" with the type of your enum
    public IEnumerable<SelectListItem> AllItems
    {
        get
        {
            return Enums.GetValues<YourEnum>().Select(enumValue => new SelectListItem { Value = enumValue.ToString(), Text = enumValue.GetDescription() });
        }
    }

모델에 SelectListItem 목록이 노출되었으므로이 속성을 소스로 사용하려면 @ Html.DropDownList 또는 @ Html.DropDownListFor를 사용할 수 있습니다.


Jon Skeet의 코드를 사용하여 +1 :), 농담이지만
Vamsi

3

이 확장 방법의 또 다른 수정-현재 버전은 열거 형의 현재 값을 선택하지 않았습니다. 마지막 줄을 수정했습니다.

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());
    }

3

현지화 지원을 추가하려면 s.toString () 메소드를 다음과 같이 변경하십시오.

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()) };

여기에서 typeof (Resources)는로드하려는 리소스이며 지역화 된 문자열을 가져옵니다. 열거 자에 여러 단어가 포함 된 값이있는 경우에도 유용합니다.


3

이것은 내 도우미 버전입니다. 나는 이것을 사용한다 :

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

그것 대신에:

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);
    }

3

Griffin.MvcContrib에서 사용자 정의 HtmlHelper를 사용할 수도 있습니다. 다음 코드 :

@Html2.CheckBoxesFor(model => model.InputType) <br />
@Html2.RadioButtonsFor(model => model.InputType) <br />
@Html2.DropdownFor(model => model.InputType) <br />

생성합니다 :

여기에 이미지 설명을 입력하십시오

https://github.com/jgauffin/griffin.mvccontrib


3

사용자가 표현 controller이나 Linq표현 을 할 필요가없는 다른 방식으로이 질문에 대답하고 싶습니다 . 이 방법...

나는 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*/
    }

이제 dropdownthis를 사용하여 간단히를 만들 수 있습니다 enum.

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

또는

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

색인을 선택하려면 다음을 시도하십시오

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

여기 AccessLevelEnum.NoAccess에서는 기본적으로 드롭 다운을 선택하기위한 추가 매개 변수로 사용 했습니다.


3

나는 여기서 답을 찾았다 . 그러나 일부 열거 형에는 [Description(...)]속성이 있으므로이를 지원하도록 코드를 수정했습니다.

    enum Abc
    {
        [Description("Cba")]
        Abc,

        Def
    }


    public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, TEnum selectedValue)
    {
        IEnumerable<TEnum> values = Enum.GetValues(typeof(TEnum))
            .Cast<TEnum>();

        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var value in values)
        {
            string text = value.ToString();

            var member = typeof(TEnum).GetMember(value.ToString());
            if (member.Count() > 0)
            {
                var customAttributes = member[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (customAttributes.Count() > 0)
                {
                    text = ((DescriptionAttribute)customAttributes[0]).Description;
                }
            }

            items.Add(new SelectListItem
            {
                Text = text,
                Value = value.ToString(),
                Selected = (value.Equals(selectedValue))
            });
        }

        return htmlHelper.DropDownList(
            name,
            items
            );
    }

희망이 도움이됩니다.


유형 = DropdownList의 멤버를 반환하고 싶습니다. 나는 Text = DescriptionAttribute에 능숙하지만 Value에서 int 값을 얻는 것이 어렵다는 것을
알았습니다.

2

@Simon Goldstone : 솔루션에 감사드립니다. 제 경우에는 완벽하게 적용 할 수 있습니다. 유일한 문제는 VB로 번역해야한다는 것입니다. 그러나 이제는 완료되었으며 다른 사람들의 시간을 절약하기 위해 (필요한 경우) 여기에 넣었습니다.

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

끝 다음과 같이 사용하십시오.

@Html.EnumDropDownListFor(Function(model) (model.EnumField))


2
@Html.DropdownListFor(model=model->Gender,new List<SelectListItem>
{
 new ListItem{Text="Male",Value="Male"},
 new ListItem{Text="Female",Value="Female"},
 new ListItem{Text="--- Select -----",Value="-----Select ----"}
}
)

2
@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" }

})

나는 이것이 올바른 대답이 아니라고 생각합니다. 드롭 다운을 채우기 위해 열거 형을 전혀 사용하지 않습니다.
앤드류
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.