ASP.NET MVCの列挙型からドロップダウンリストを作成するにはどうすればよいですか?


668

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以下の場合

私はルーンの答えを拡張メソッドに入れました:

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プロパティですか?これは列挙値の1つではありませんか?
ダリル

9
あなたがそれを少し制限することができます。ここで、T:構造体、IConvertible参照:stackoverflow.com/questions/79126/...
リチャード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:マイクロソフトはMVC 5.1をリリースしました。これにEnumDropDownListFor機能が追加されました。悲しいことに、[説明]属性を尊重していないように見えるため、上記のコードはまだ有効です。MicrosoftのMVC 5.1リリースノートの列挙型セクションを参照してください。

更新:ただし、Display属性はサポートされているため[Display(Name = "Sample")]、これを使用できます。

[更新-これに気づきました。コードは次のコードの拡張バージョンのように見えます:https : //blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- dropdownlist-helper-for-enums /、いくつか追加。もしそうなら、帰属は公正に見えるでしょう;-)]


28
+1ここですべての回答の中でこれが最も有用であることがわかりました。これを非常に再利用可能なコードに変えることができました。ありがとうございました!
エドシャルベノー

43
Visual Studioは、あなたが参照しない場合は、奇妙なバグがありませんSystem.Web.Mvc.Html、それはそれは言う、その後DropDownListFor見つけることができないが、しかしどちらも、それはそれを解決することができます。手動で行う必要がありますusing System.Web.Mvc.Html;。本当にそうだね。
Kezzer、2011年

1
私はすべてのプロジェクトで使用する要点にこれのバリアントがあります:gist.github.com/1287511
kamranicus

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、2015年

2
EnumDropDownListFor()について私が気に入らないのは、テキストではなく列挙型のint値がDBに保存されるため、新しい列挙型項目を追加することを選択した場合は、必ずリストの最後に移動する必要があることです。 、保存されたデータベースのint値と列挙型アイテムの元の位置との関係が失われないようにするため。テキストを保存する場合、これは不要な制限です。さらに、intではなく、dbを見てテキストを見ることができるため、別の場所でテキスト値を検索する必要があります。それ以外の場合は、このhtmlヘルパーを使用すると非常に便利です。
ジョヴァンニ

2
@Giovanni-独自の数値を指定できます。
Tommy

1
@Giovanniの厳密な設計では、各enumエントリに値を割り当てる必要があります(重要な場合)。それ以外の場合、値は問題になりません(したがって、新しいものを最後に配置しても問題はありません)。ストレージの節約とパフォーマンスの向上(検索を実行する場合)に関しては、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);

これは良いolを作成します SelectList、ビューで慣れているように使用できるします。

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

匿名型とLINQにより、これは非常にエレガントなIMHOになります。アッシュ、意図した攻撃はありません。:)


いい答えです!私は誰かがlinqとSelectListを使用することを望んでいました:)ここで最初にチェックしてよかったです!
Pure.Krome 2009年

1
ID = sは値ではなくDataTextFieldを与えますか?その理由は何でしょうか?ありがとう
Barbaros Alp

1
ルーン、私はこれと同じメソッドを使用し、DropDownListはまだサーバーにポストするときにレンダリングしますが、選択した値を保存しません。
clockwiseq

5
:あなたはintに列挙型にキャストする必要があります数であるようにIDのために@BarbarosAlpselect new { ID = (int)s, Name = s.ToString() };
キース

これは、その単純さのために私が最も好きな答えです。選択した回答がソリューションを使用したため、十分なクレジットが得られなかったのは残念です。
anar khalilov 2013年

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属性を使用するオプションが好きです。ダウンロードせずにコピーアンドペーストできるようにコードを追加しました。
ベン・ミルズ

EnumDropDownListForとして拡張メソッドではなくDropDownListFor使用法を呼び出す: - > @ Html.EnumDropDownListFor(X => x.Gender)
サンディープのtalabathula

もう1つの要素「選択してください」を追加しようとしている場合return htmlHelper.DropDownListFor(expression、createSelectList(expression.ReturnType、selected、firstElement)、 "Select Select");
Sandeep、2014

1
正常に動作します!ただし、[詳細]ページでは、DisplayFor()は対応する説明の代わりに列挙型の選択された値を表示します。これは列挙型のDisplayFor()のオーバーロードを必要とすると思います。誰かがこれに対する解決策を持っていますか?
corix010

48

Html.DropDownListForは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」と何か関係がある含まれる
学習者

@Cristi、その通りです。このソリューションは、モデルがnullである状況で使用することを意図していません。私はそのようなデザインを一般的に回避し、そうである場合は「空の」モデルに初期化しようとします。
Zaid Masud 2012年

まあ、私はasp mvcは初めてですが、.Netでかなりの経験があります。ありがとう、あなたが提案していたことを調べます。ところで、ToDescription拡張機能は 'Enum'スコープのはるか外にあります。私は「オブジェクト」自体にうまくいくと思います。これは、サイモンのコードを取得してもう少しクリーンアップしたときに使用したものです。
学習者2012年

@Cristi「 'Enum'スコープのはるか外側」という意味を理解することは困難ですが、ToDescription拡張メソッドがItemTypes列挙型に強く型付けされていないと言っているようです。これは意図的なものであり、拡張メソッドをすべての列挙型で一般的に使用できるようにします。それを一般的な拡張メソッドと比較する場合、各アプローチの長所と短所があります。特に、generecizeする場合、列挙型だけに制約を課すことはできません。
Zaid Masud 2012年

1
ありがとうございます。value.ToStringを変更して、説明がない場合に拡張FromCamelCaseを使用するようにしました。それが私が転がる方法です:)
ヴァラマス

33

シンプルで簡単なものを探しているなら、エクステンション関数は必要ありません。

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

ここで、XXXXX.Sites.YYYY.Models.Stateは列挙型です

おそらくヘルパー機能を実行する方が良いですが、時間が短い場合はこれで仕事が完了します。


これはドロップダウンを作成するのにうまくいきましたが、Html.DropDownListForのRazor構文でデフォルトの選択値をどのように設定しますか?列挙型のコンボボックスを含むテーブルを表示したいのですが、以前と同じように選択した値も設定する必要があります。
Johncl、2011

2
選択した値を持つ2番目のパラメーターを新しいSelectList(IEnumerable、object)関数に渡すことができる必要があります。MSDNドキュメント:msdn.microsoft.com/en-us/library/dd460123.aspx
Marty Trenouth

23

PrizeとRuneの回答を拡張して、選択リスト項目のvalue属性を文字列値ではなく列挙型の整数値にマッピングする場合は、次のコードを使用します。

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オブジェクトとして扱う代わりに、それをオブジェクトとして扱い、それを整数にキャストして、ボックス化されていない値を取得できます。

注: この拡張機能が使用できる型を構造体(列挙型の基本型)のみに制限する汎用型制約と、渡された構造体が実際に列挙型であることを確認するランタイム型検証も追加しました。

更新10/23/12: 基になる型のジェネリック型パラメーターを追加し、.NET 4+に影響を与える非コンパイルの問題を修正しました。


ありがとう!これが私が必要とした答えでした。Enumの整数値をデータベースの列として格納していますが、このソリューションは完全に機能しているようです。
grimus

しかし、intではなくcharを格納している場合はどうなりますか?これは私の場合です。明らかに(int)を(char)に変更できますが、これもジェネリックにするのはどうですか?どうやってするか?
Stefanvds、2009

@Stefandvdsこれは、正しい表現型へのキャストに関して素晴らしい質問です。先ほど実行したテストに基づいて、実際の型を別の型パラメーターとして指定することでこれを達成できる唯一の方法のように思われます。ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... }
Nathan Taylor


列挙型の値がintの場合は、単にを使用できますValue = Convert.ToInt32(e)(int)eコンパイルしません。:(
アンドリュー

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は、あなたが直接キャストせません私はなぜだろうeint
Andrew、

または、単にを使用することもできますID = Convert.ToInt32(e)
アンドリュー

11

これを実行する非常に簡単な方法-やり過ぎと思われる拡張機能をすべて使用しない場合は次のようになります。

あなたの列挙型:

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

コントローラの内部で、列挙型をリストにバインドします。

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

これは私が見つけた最も簡単な方法であり、拡張機能やクレイジーなものを必要としません。

更新:以下のアンドリュースのコメントを参照してください。


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 Razor。ビューまたはランタイムで、error = "次のメソッドまたはプロパティ間で曖昧な呼び出し 'LDN.Extensions.MvcExtensions.EnumDropDownListFor <MyModel、LDN.Models.YesPartialNoEnum?>(System.Web.Mvc.HtmlHelper <MyModel>、System .Linq.Expressions.Expression <System.Func <MyModel、LDN.Models.YesPartialNoEnum?>>) 'and ...
2012


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)を選択リストのテキストとして取得する必要があります
Dmitresky

7

これは、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()) %>

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>

ToSelectListonの呼び出しに使用するアイテムが選択されたアイテムであることに注意してください。


または、単にを使用することもできます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で始まる連続した値で構成されている場合にのみ機能します。Flags列挙型はこれでは機能しません。ただし、インデックス付きSelectのクリエイティブな使用。
Suncat2000

6

.NET Coreでは、これを使用できます。

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

1
または、タグヘルパーを使用し<select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList<MyEnum>()"></select>ます。
Pascal R.

うん

また、これを行うことができます@ Html.DropDownListFor(x => x.Foo、Html.GetEnumSelectList(typeof(FooEnum)))
Fereydoon Barikzehy


5

Simonの回答に基づいて、同様のアプローチは、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();
}

ItemTypes_MovieのようなEnums.Resxファイル内のリソース:Film

私がしたいもう1つのことは、拡張メソッドを直接呼び出すのではなく、@ Html.EditorFor(x => x.MyProperty)で呼び出すか、理想的にはフォーム全体を1つの整然とした@で呼び出すことです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

私はこれに非常に遅れていますが、Unconstrained Melody NuGetパッケージ(Jon Skeetの素敵な小さなライブラリ)を追加してよければ、1行のコードでこれを行う本当にクールな方法を見つけました。

このソリューションは、次の理由により優れています。

  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を使用できます。


ジョン・スキートのコードを使用するための+1 :)、ただ良いものをからかっているだけ
Vamsi

3

この拡張メソッドのもう1つの修正-現在のバージョンでは、列挙型の現在の値が選択されませんでした。最後の行を修正しました:

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

別の方法でこの質問に答えたいのですが、ユーザーは何もする必要がない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*/
    }

これで、これをdropdown使用して単純にを作成できます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

End次のように使用します。

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

})

これは有効な答えではないと思います。ドロップダウンの入力にenumをまったく使用していません。
アンドリュー、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.