ASP.NET MVC bir numaralandırma bir açılan liste nasıl oluştururum?


671

Html.DropDownListUzantı yöntemini kullanmaya çalışıyorum ama bir numaralandırma ile nasıl kullanılacağını anlayamıyorum.

Diyelim ki böyle bir numaralandırmam var:

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

Html.DropDownListExtension yöntemini kullanarak bu değerlerle bir açılır liste oluşturmaya nasıl gidebilirim ?

Yoksa sadece bir for döngüsü oluşturmak ve Html öğelerini manuel olarak oluşturmak için en iyi seçeneğim mi?

Yanıtlar:


842

MVC v5.1 için Html.EnumDropDownListFor kullanın

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

MVC v5 için EnumHelper kullanın

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

MVC 5 ve altı için

Rune'un cevabını bir uzatma yöntemine yuvarladım:

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

Bu şunları yazmanıza izin verir:

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

tarafından using MyApp.Common


13
Çalıştıramadım, lütfen yardım eder misin? Ne zaman Post.PostType.ToSelectList (); uzantıyı tanımıyor?
Barbaros Alp

3
Ben de işe yaramadı. Görev sınıfındaki Enum Özelliğiniz Durumu mu? Bu numaralandırılmış değerlerden biri değil mi?
Daryl

9
Biraz ile sınırlandırabilirsiniz: burada T: struct, IConvertible Bkz: stackoverflow.com/questions/79126/…
Richard

8
Bu havalı. Eğer kimse w / uygulama ile mücadele ediyorsa, bunu nasıl yaptım. HtmlHelpers klasörüne bir EnumHelpers sınıfı eklendi. Yukarıdaki kod kullanıldı. @TodK önerisi başına ad alanı eklendi: <add namespace = "xxx.HtmlHelpers" />. Sonra böyle bir jilet sayfasında kullandım: @ Html.DropDownListFor (model => model.Status, @ Model.Status.ToSelectList ()) HTH
Jeff Borden

6
Daha yeni ASP.NET MVCbir yerel yol olduğunu unutmayın: stackoverflow.com/a/22295360/1361084
Ofiris

359

Bu partiye geç kaldığımı biliyorum, ancak bu varyantı yararlı bulabileceğinizi düşündüm, çünkü bu da açılır listede numaralandırma sabitleri yerine açıklayıcı dizeler kullanmanıza izin verir. Bunu yapmak için, her numaralandırma girdisini bir [System.ComponentModel.Description] özniteliğiyle süsleyin.

Örneğin:

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

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

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

İşte benim kod:

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

Daha sonra bunu görünümünüzde yapabilirsiniz:

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

Umarım bu size yardımcı olur!

** EDIT 2014-JAN-23: Microsoft, şimdi bir EnumDropDownListFor özelliği olan MVC 5.1'i piyasaya sürdü. Ne yazık ki yukarıdaki kod hala duruyor böylece [Açıklama] özniteliğine saygı gibi görünmüyor . Microsoft'un MVC 5.1 sürüm notlarındaki Enum bölümüne bakın .

Güncelleme: Display özniteliğini destekliyor [Display(Name = "Sample")], böylece bunu kullanabilirsiniz.

[Güncelleme - bunu fark etti ve kod burada kodun genişletilmiş bir sürümüne benziyor: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a- birkaç eklenti ile açılır liste-yardımcıları için yardımcı / . Eğer öyleyse, atıf adil görünecektir ;-)]


28
+1 Bunu tüm cevaplar için en yararlı buldum. Bunu oldukça yeniden kullanılabilir bir kod parçasına dönüştürebildim. Teşekkür ederim!
Ed Charbeneau

43
Visual Studio, eğer System.Web.Mvc.Htmlbaşvurmazsanız, DropDownListForbulunamayacağını söyleyen garip bir hata vardır , ancak bunu çözemez. Manuel olarak yapmalısınız using System.Web.Mvc.Html;. Sadece biliyorsun.
Kezzer

1
Tüm projelerimizde kullandığımız bir özette
kamranicus

1
GetEnumDescription
M. Mennan Kara

17
Yeni MVC 5.1 EnumDropDownListFor [Açıklama ("")] kullanmıyor ancak [Display (Name = "")] kullanıyor! Keyfini çıkarın :)
Supergibbs

195

In ASP.NET MVC 5.1 , onlar ekledi EnumDropDownListFor()yardımcı yüzden özel uzantıları gerek:

Model numarası :

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

Görüntüle :

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

Etiket Yardımcısı'nı (ASP.NET MVC 6) kullanma :

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

21
Bu bir şekilde ilk yere kadar

3
MVC 5.1'e özgü yeni bir soru oluşturmalı ve bunu cevap olarak koymalısınız, daha sonra bir favoriyi onaylayabilmem için bana gönderinin bağlantısını göndermelisiniz.
Kevin Heidt

2
EnumDropDownListFor () hakkında sevmediğim, DB'ye enum'un int değerini değil, metni kaydetmesidir, bu yüzden yeni bir enum öğesi eklemeyi seçerseniz, mutlaka listenin sonuna gitmelidir , kaydedilen veritabanı int değerlerinin numaralandırma öğelerinin özgün konumlarıyla ilişkisini kaybetmemek için. Metin kaydedilmişse bu gereksiz bir kısıtlamadır. Artı, ben daha sonra başka bir yerde metin değerleri aramak zorunda ints yerine, db bakmak ve bir metin görmek mümkün. Aksi takdirde bu html yardımcısının kullanımı çok uygundur.
Giovanni

2
@Giovanni - kendi sayısal değerlerinizi belirleyebilirsiniz.
Tommy

1
@Giovanni Katı tasarım, her bir numaralandırma girişi için değer atamalıdır (eğer önemliyse), aksi takdirde değer önemli olmamalıdır (ve böylece yenilerini sonuna yerleştirmek sorun olmamalıdır). Depolama alanından tasarruf etmek ve performansı artırmak (int biraz arama yaparken) için int değerlerini kaydetmek daha iyidir.
King King

130

Aynı soruna çarptım, bu soruyu buldum ve Ash'in sağladığı çözümün aradığım şey olmadığını düşündüm; HTML'yi kendim oluşturmak, yerleşik Html.DropDownList()işleve göre daha az esneklik anlamına gelir .

C # 3 vb. Çıkıyor. Bir enumçağrı var 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);

Bu SelectList, görünümde alıştığınız gibi kullanılabilecek iyi bir ol oluşturur :

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

Anonim tip ve LINQ bunu çok daha şık IMHO yapar. Saldırı amaçlı değil Ash. :)


iyi cevap! birisi linq ve SelectList kullanmak umuyordum :) Sevindim ben ilk burada kontrol!
Pure.Krome

1
ID = s bana DataTextField değerini değil verir mi? Nedeni ne olabilir? Thank you
Barbaros Alp

1
Rune, aynı yöntemi kullandım ve DropDownList, sunucuya gönderirken henüz render yapar, seçtiğim değeri kaydetmez.
saat

5
@BarbarosAlp ID'nin bir sayı olması için, numaralandırmayı bir int'e yayınlamanız gerekir:select new { ID = (int)s, Name = s.ToString() };
Keith

Sadeliği nedeniyle en çok sevdiğim cevap bu. Seçilen cevap çözümünüzü kullandığı için yeterince kredi alamadığınız için yazık.
anar khalilov

63

İşte daha iyi bir kapsüllenmiş çözüm:

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

Diyelim ki modeliniz:

resim açıklamasını buraya girin

Örnek Kullanımı:

resim açıklamasını buraya girin

Oluşturulan kullanıcı arayüzü: resim açıklamasını buraya girin

Ve oluşturulan HTML

resim açıklamasını buraya girin

Yardımcı Uzantı Kaynak Kodu ek çekimi:

resim açıklamasını buraya girin

Örnek projeyi sağladığım bağlantıdan indirebilirsiniz.

EDIT: İşte kod:

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
Sadece benim düşüncem, ama bence bu cevap kabul edilen cevaptan çok daha temiz. Özellikle Description özniteliğini kullanma seçeneğini seviyorum. Kullanıcıları indirmeden kopyalayıp yapıştırabilmeleri için kodu ekledim.
Ben Mills

Uzantı yöntemini DropDownListFor Kullanım yerine EnumDropDownListFor olarak çağırın: -> @ Html.EnumDropDownListFor (x => x.Gender)
sandeep talabathula

Bir öğe daha eklemek istiyor Birisi için "Lütfen Seçin" return htmlHelper.DropDownListFor (expression, createSelectList (expression.ReturnType, seçili, firstElement), "Please Select");
Sandeep

1
İyi çalışıyor! Ancak Ayrıntılar sayfasında DisplayFor (), ilgili açıklama yerine enum'un seçili değerini gösterir. Bu numaralandırma türü için DisplayFor () aşırı yükleme gerektirdiğini varsayalım. Bunun çözümü olan var mı?
corix010

48

Html.DropDownListFor sadece bir IEnumerable gerektirir, bu nedenle Prise çözümüne bir alternatif aşağıdaki gibidir. Bu, şunları yazmanıza olanak tanır:

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

[SelectedItemType öğesinin, ItemTypes türü modelinizde bir alan olduğu ve modelinizin boş olmadığı durumlarda]

Ayrıca, typeof (T) yerine enumValue.GetType () kullanabileceğiniz için, uzantı yöntemini genel olarak genelleştirmeniz gerekmez.

EDIT: Simon çözümünü de buraya entegre etti ve ToDescription genişletme yöntemini içeriyordu.

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

Benim için çalışmıyor ('System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı.') ... 'Modelim' boş ... muhtemelen Simon'un sahip olduğu 'GetNonNullableModelType' ile ilgisi var dahil
Öğrenci

@Cristi, haklısınız, bu çözüm Modelinizin boş olduğu bir durumda kullanılmak üzere tasarlanmamıştır. Genel olarak böyle bir tasarımdan kaçınmaya ve durum böyle olduğunda "Boş" bir modele başlamaya çalışıyorum.
Zaid Mesud

Eh, ben asp mvc için yeni, ama .Net oldukça deneyime sahip. Teşekkür ederim, önerdiğinize bakacağım. Ancak ToDescription uzantınız 'Enum' kapsamının çok dışında. Sanırım 'Nesne'nin kendisi için iyi gidiyor. Simon kodunu alıp biraz daha temizlediğimde kullandığım şey bu.
Öğrenci

@Cristi "Enum" kapsamının çok dışında ne demek istediğinizi anlamak zor ama ToDescription uzantı yönteminin ItemTypes enum'a güçlü bir şekilde yazılmadığını söylediğiniz anlaşılıyor mu? Bu kasıtlıdır ve genişletme yöntemini tüm numaralandırmalar tarafından genel olarak kullanılabilir hale getirir. Bunu genel bir genişletme yöntemiyle karşılaştırıyorsanız, her yaklaşımın artıları ve eksileri vardır. Özellikle, eğer jenerik yaparsanız, bunu sadece numaralandırmalarla sınırlandıramazsınız.
Zaid Masud

1
Harika, teşekkürler. Herhangi bir açıklama olmaması durumunda FromCamelCase uzantısını kullanmak için value.ToString'i değiştirdim. Bu şekilde yuvarlanıyorum :)
Valamas

33

Yani basit ve kolay arıyorsanız Uzatma fonksiyonları olmadan .. Ben bunu yaptım

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

burada XXXXX.Sites.YYYY.Models.State bir numaralandırmadır

Muhtemelen yardımcı işlevi yapmak daha iyidir, ancak zaman kısa olduğunda bu işi halledecektir.


Bu güzel açılır listeyi doldurmak çalıştı ama Html.DropDownListFor için Razor sözdiziminde varsayılan seçilen değeri nasıl ayarlarsınız? Komut kutularının birleşik kutularını içeren bir tablo göstermek istiyorum ve seçilen değeri daha önce ne olduğuna göre ayarlamam gerekiyor.
Johncl

2
Seçilen değerle ikinci bir parametreyi yeni SelectList (IEnumerable, object) işlevine geçirebilmelidir. MSDN Dokümantasyonu: msdn.microsoft.com/en-us/library/dd460123.aspx
Marty Trenouth

23

Ödül ve Rune yanıtlarına genişleyerek, seçtiğiniz liste öğelerinin değer özelliğinin dize değeri yerine Numaralandırma türünün tamsayı değeriyle eşleşmesini istiyorsanız, aşağıdaki kodu kullanın:

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

Her bir Enumeration değerini bir TEnum nesnesi olarak ele almak yerine, nesneyi ele alabilir ve kutusuz değeri almak için tamsayıya atabiliriz.

Not: Ayrıca, bu uzantının yalnızca yapılar (Enum'un temel türü) tarafından kullanılabileceği türleri sınırlamak için genel bir tür kısıtlaması ve iletilen yapının gerçekten bir Enum olmasını sağlayan bir çalışma zamanı türü doğrulaması ekledim.

Güncelleme 10/23/12: Temel tür için genel tür parametresi eklendi ve .NET 4+ 'u etkileyen derleme dışı sorun düzeltildi.


Teşekkürler! İhtiyacım olan cevap buydu. Ben veritabanında bir sütun olarak bir Enum tamsayı değeri saklıyorum ve bu çözüm mükemmel çalışıyor gibi görünüyor.
Grimus

Peki ya bir int değil bir char saklıyorsanız? bu benim durumum. Açıkçası (int) (char) değiştirmek olabilir ama nasıl da bu jenerik yapmak hakkında. bu nasıl yapılır?
Stefanvds

@Stefandvds Bu, doğru temsil edilen türe döküm açısından harika bir soru. Yeni yaptığım testlere dayanarak, bunu gerçekleştirmenin tek yolu gerçek türü başka bir tür parametresi olarak belirtmek olacaktır. ToSelectList<TEnum, TEnumValue>(this TEnum enumObj) { ... }
Nathan Taylor


Numaralandırmanızın değerleri int ise, bunu kullanabilirsiniz Value = Convert.ToInt32(e). (int)ederlemez. :(
Andrew

11

Prise'nin uzatma yöntemini kullanarak metin yerine sayı alma problemini çözmek.

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

Aradığım şey buydu, ancak olması gerektiğini düşündüğümden daha çirkin bir şeydi. Ben Visual Studio doğrudan döküm vermeme sebebim merak eetmek int.
Andrew

Veya sadece kullanabilirsiniz ID = Convert.ToInt32(e).
Andrew

11

Bunu yapmanın süper kolay bir yolu - overkill gibi görünen tüm uzantı öğeleri olmadan:

Numaralandırmanız:

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

Denetleyicinizin içi, Numaralandırmayı bir Listeye bağlar:

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

Bundan sonra bir ViewBag içine atın:

    ViewBag.RequiredLevel = new SelectList(myLevels);

Son olarak Görünüm'e bağlayın:

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

Bu, bulduğum en kolay yoldur ve herhangi bir uzantı veya çılgın bir şey gerektirmez.

GÜNCELLEME : Aşağıdaki Andrews yorumuna bakın.


3
Bu yalnızca numaralandırmanıza herhangi bir değer atamadıysanız çalışır. Eğer olsaydı Level1 = 1, açılır listenin değeri "Level1"yerine olurdu 1.
Andrew

11

Bunun için bulduğum en iyi çözüm, bu blogu Simon Goldstone'un cevabı ile birleştirmekti .

Bu, enumun modelde kullanılmasına izin verir. Esasen, enumun yanı sıra bir tamsayı özelliği kullanmak ve tamsayı özelliğini taklit etmektir.

Ardından, modele görüntü metninizle açıklama eklemek için [System.ComponentModel.Description] özniteliğini ve görünümünüzde bir "EnumDropDownListFor" uzantısı kullanın.

Bu, hem görünümü hem de modeli çok okunabilir ve bakımı yapılabilir hale getirir.

Model:

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

Görünüm:

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

Uzatma (doğrudan Simon Goldstone'un cevabından , tamlık için buraya dahil edilmiştir):

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

Bu işe yaramaz, MVC 4 Razor. Görünümde veya çalışma zamanında error = "Aşağıdaki yöntemler veya özellikler 'LDN.Extensions.MvcExtensions.EnumDropDownListFor <MyModel, LDN.Models.YesPartialNoEnum?> (System.Web.Mvc.HtmlHelper <MyModel>, Sistem Açıklama.
Marc


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

İyi! Bu şekilde numaradan değer ve metin nasıl alınır? Ben SomeEnum {Some1 = 1, some2 = 2} Ben SelectList metninde değeri ve metin (some1, some2) için sayıları (1, 2) almak gerekir anlamına
Dmitresky

7

Bu Numaralandırma'yı kullanmak için değiştirilen Rune & Prize cevapları int değerini kimlik olarak .

Örnek Numaralandırma:

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

Genişletme yöntemi:

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

Kullanım örneği:

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

Extension yöntemini içeren ad alanını almayı unutmayın

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

Oluşturulan HTML örneği:

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

On'u aramak için kullandığınız ToSelectListöğenin seçilen öğe olduğunu unutmayın.


Veya sadece kullanabilirsiniz Id = Convert.ToInt32(e).
Andrew

6

Bu Razor sürümü:

@{
    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)

Bu yalnızca enum değeriniz 0 ile başlayan bitişik değerlerden oluşuyorsa işe yarar. A Flags enum bununla çalışmaz. Bununla birlikte, dizine alınan Seçkin öğelerin yaratıcı kullanımı.
Suncat2000

6

.NET Core'da şunları kullanabilirsiniz:

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

1
Veya etiket yardımcısıyla <select asp-for="Model.Foo" class="form-control" asp-items="@Html.GetEnumSelectList<MyEnum>()"></select>.
Pascal R.7

Evet, Id biçim yardımcıları biçim saf HTML daha yakın olduğu gibi daha iyi söylüyorlar;)
GoldenAge

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


5

Simon'un cevabına dayanarak, benzer bir yaklaşım Enum değerlerinin, Enum'un kendi içindeki bir açıklama özniteliği yerine bir Kaynak dosyasından görüntülenmesini sağlamaktır. Sitenizin birden fazla dilde işlenmesi gerekiyorsa ve Numaralandırmalar için belirli bir kaynak dosyanız varsa, bir adım daha ileri gidebilir ve Numaralandırmanızda yalnızca Enum değerlerine sahip olabilir ve [EnumName] _ [EnumValue] gibi bir kural - sonuçta daha az yazım!

Sonra uzantı şöyle görünür:

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 dosyasındaki ItemTypes_Movie: Film benzeri kaynaklar

Yapmak istediğim başka bir şey, doğrudan uzatma yöntemini çağırmak yerine, bir @ Html.EditorFor (x => x.MyProperty) ile çağırmayı veya ideal olarak tüm formu tek bir temiz @ Html.EditorForModel (). Bunu yapmak için dize şablonunu şöyle görünecek şekilde değiştiririm

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

Bu ilginizi çekiyorsa, buraya blogumda çok daha ayrıntılı bir cevap koydum:

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


5

Partiye gerçekten geç kaldım, ama ne kadar değerli olduğu için, bu konuda EnumHelperçok kolay dönüşüm sağlayan bir sınıf oluşturduğum için blog yazdım .

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

Kumandanızda:

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

Görüşünüze göre:

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

Yardımcı sınıf:

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

Bu konuda çok geç kaldım, ancak Kısıtlanmamış Melody NuGet paketini (Jon Skeet'ten güzel, küçük bir kütüphane) eklemekten mutluluk duyuyorsanız, bunu bir kod satırı ile yapmanın gerçekten harika bir yolunu buldum .

Bu çözüm daha iyidir çünkü:

  1. (Genel tip kısıtlamaları ile) değerin gerçekten bir enum değeri olmasını sağlar (Kısıtlanmamış Melodi nedeniyle)
  2. Gereksiz boksu önler (Kısıtsız Melodi nedeniyle)
  3. Her çağrıda yansıma kullanmaktan kaçınmak için tüm açıklamaları önbelleğe alır (Kısıtlanmamış Melodi nedeniyle)
  4. Diğer çözümlerden daha az kod!

İşte, bu çalışmayı sağlamak için adımlar:

  1. Paket Yöneticisi Konsolu'nda, "Install-Package UnconstrainedMelody"
  2. Modelinize şöyle bir özellik ekleyin:

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

Şimdi modelinizde SelectListItem listesi açık olduğundan, @ Html.DropDownList veya @ Html.DropDownListFor bu özelliği kaynak olarak kullanarak kullanabilirsiniz.


Jon Skeet'in kodunu kullanmak için +1, sadece iyi olanı şaka yapıyorum
Vamsi

3

Bu uzantı yöntemine başka bir düzeltme - geçerli sürüm enum'un geçerli değerini seçmedi. Son satırı düzelttim:

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

Yerelleştirme desteği eklemek istiyorsanız, s.toString () yöntemini şu şekilde değiştirin:

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

Burada typeof (Resources) (Kaynak) yüklemek istediğiniz kaynaktır ve daha sonra yerelleştirilen String'i alırsınız.


3

Bu benim yardımcı yöntem versiyonum. Bunu kullanıyorum:

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

Bunun yerine:

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

İşte burada:

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

Özel HtmlHelpers'ımı Griffin.MvcContrib içinde de kullanabilirsiniz. Aşağıdaki kod:

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

üretir:

resim açıklamasını buraya girin

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


3

Bu soruya, kullanıcının herhangi bir şey controllerveya Linqifade yapmasına gerek olmadığı farklı bir şekilde cevaplamak istiyorum . Bu yoldan...

Sahibim 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*/
    }

Şimdi bunu dropdownkullanarak sadece bir canto oluşturabilirim enum.

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

VEYA

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

Bir dizin seçilmesini istiyorsanız bunu deneyin

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

Burada AccessLevelEnum.NoAccessvarsayılan açılır listeyi seçmek için ekstra bir parametre olarak kullandım .


3

Burada bir cevap buldum . Ancak, bazı numaralandırmalar [Description(...)]özniteliği var, bu yüzden bunun için destek sağlamak için kodu değiştirdim:

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

Umarım yardımcı olur.


= DropdownList türünde bir üye döndürmek istiyorum. Metin = DescriptionAttribute ile iyiyim ama Değer int değerini almak zor bulmak
NanaFadanvis

2

@Simon Goldstone: Çözümünüz için teşekkürler, benim durumumda mükemmel bir şekilde uygulanabilir. Tek sorun VB'ye çevirmek zorunda kaldım. Ama şimdi yapıldı ve diğer insanların zamanını kurtarmak için (ihtiyaç duymaları durumunda) buraya koydum:

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

Son Şu şekilde kullanırsınız:

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

})

Bunun geçerli bir cevap olmadığını düşünüyorum, açılır listeyi doldurmak için enum'u hiç kullanmıyor.
Andrew
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.