741 Stimmen

Wie erstellen Sie eine Dropdownliste aus einer Aufzählung in ASP.NET MVC?

Ich versuche, die Html.DropDownList Erweiterungsmethode, kann aber nicht herausfinden, wie man sie mit einer Aufzählung verwenden kann.

Nehmen wir an, ich habe eine Aufzählung wie diese:

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

Wie erstelle ich eine Auswahlliste mit diesen Werten unter Verwendung der Html.DropDownList Erweiterungsmethode?

Oder ist meine beste Wette, um einfach eine for-Schleife erstellen und die Html-Elemente manuell erstellen?

907voto

Martin Faartoft Punkte 3275

Für MVC v5.1 verwenden Sie Html.EnumDropDownListFor

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

Für MVC v5 verwenden Sie EnumHelper

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

Für MVC 5 und niedriger

Ich habe die Antwort von Rune in eine Erweiterungsmethode umgewandelt:

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

Dies ermöglicht es Ihnen zu schreiben:

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

von using MyApp.Common

13 Stimmen

Ich konnte es nicht zum Laufen bringen, könnten Sie bitte helfen. Wenn ich Post.PostType.ToSelectList(); tue, erkennt es die Erweiterung nicht?

3 Stimmen

Ich konnte das auch nicht zum Laufen bringen. Ist Status Ihre Enum-Eigenschaft in der Aufgabenklasse? Ist dies nicht einer der Aufzählungswerte?

1 Stimmen

Großartig! Zu den Fragen oben: Ja, es ist einer der Aufzählungswerte, der zum "ausgewählten Wert" wird. Sie können auch tun: ((TypesEnum)typeId).ToSelectList();

378voto

SimonGoldstone Punkte 4983

Ich weiß, ich bin spät dran, aber ich dachte, Sie könnten diese Variante nützlich finden, da sie Ihnen auch erlaubt, beschreibende Zeichenfolgen anstelle von Aufzählungskonstanten in der Dropdown-Liste zu verwenden. Um dies zu tun, dekorieren Sie jeden Aufzählungseintrag mit einem [System.ComponentModel.Description]-Attribut.

Zum Beispiel:

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

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

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

Hier ist mein Code:

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

Sie können dies dann in Ihrer Ansicht tun:

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

Ich hoffe, das hilft Ihnen!

**ÄNDERUNG 2014-JAN-23: Microsoft hat gerade MVC 5.1 veröffentlicht, das nun eine EnumDropDownListFor-Funktion hat. Leider scheint es nicht das [Description]-Attribut zu respektieren, so dass der Code oben noch steht. Enum-Abschnitt in Microsofts Versionshinweise für MVC 5.1.

Update: Das Programm unterstützt die Anzeige Attribut [Display(Name = "Sample")] aber das kann man verwenden.

[Update - ich habe dies gerade bemerkt, und der Code sieht aus wie eine erweiterte Version des Codes hier: https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/ mit ein paar Ergänzungen. Wenn ja, dann wäre eine Namensnennung angebracht ;-)]

30 Stimmen

+1 Von allen Antworten hier fand ich diese am nützlichsten. Ich war in der Lage, dies in ein sehr wiederverwendbares Stück Code zu verwandeln. Ich danke Ihnen!

44 Stimmen

Visual Studio hat einen seltsamen Fehler, bei dem, wenn Sie nicht auf System.Web.Mvc.Html dann heißt es, dass DropDownListFor kann nicht gefunden werden, aber es kann auch nicht gelöst werden. Sie müssen manuell Folgendes tun using System.Web.Mvc.Html; . Nur damit Sie es wissen.

1 Stimmen

Ich habe eine Variante davon in einer Gist, die wir in allen unseren Projekten verwenden: gist.github.com/1287511

224voto

Ofiris Punkte 5897

Unter ASP.NET MVC 5.1 fügten sie die EnumDropDownListFor() Helper, so dass keine benutzerdefinierten Erweiterungen erforderlich sind:

Modell :

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

Siehe :

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

Tag Helper verwenden (ASP.NET MVC 6) :

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

4 Stimmen

Sie sollten eine neue Frage, die spezifisch für MVC 5.1 und setzen Sie diese als die Antwort, dann senden Sie mir einen Link zu dem Beitrag, so dass ich kann upvote ein Favorit.

3 Stimmen

Was mir an EnumDropDownListFor() nicht gefällt, ist, dass der int-Wert der Aufzählung in der DB gespeichert wird, nicht der Text. Wenn Sie also ein neues Aufzählungselement hinzufügen möchten, muss es zwangsläufig am Ende der Liste stehen, damit die Beziehung zwischen den gespeicherten int-Werten der Datenbank und den ursprünglichen Positionen der Aufzählungselemente nicht verloren geht. Das ist eine unnötige Einschränkung, wenn der Text gespeichert wird. Außerdem ist es mir lieber, ich kann in der Datenbank nachsehen und sehe einen Text, als dass ich die Text-Werte an anderer Stelle nachschlagen muss. Ansonsten ist diese Html-Hilfe sehr bequem zu benutzen.

3 Stimmen

@Giovanni - Sie können Ihre eigenen numerischen Werte angeben.

137voto

Rune Jacobsen Punkte 9597

Ich bin auf das gleiche Problem gestoßen, habe diese Frage gefunden und dachte, dass die von Ash angebotene Lösung nicht das ist, was ich suche; wenn ich das HTML selbst erstellen muss, bedeutet das weniger Flexibilität im Vergleich zu den integrierten Html.DropDownList() Funktion.

Es stellte sich heraus, dass C#3 usw. dies ziemlich einfach macht. Ich habe eine enum genannt. 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);

Dies schafft eine gute alte SelectList die Sie wie gewohnt in der Ansicht verwenden können:

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

Die anonyme Art und LINQ macht dies so viel mehr elegant IMHO. Nicht böse gemeint, Ash :)

0 Stimmen

Gute Antwort! Ich hatte gehofft, jemand würde linq und die SelectList verwenden :) Gut, dass ich zuerst hier nachgesehen habe!

1 Stimmen

ID = s gibt mir das DataTextField und nicht den Wert? Was könnte der Grund dafür sein? Ich danke Ihnen

1 Stimmen

Rune, ich habe dieselbe Methode verwendet und die DropDownList wird gerendert, aber wenn sie an den Server gesendet wird, wird der von mir ausgewählte Wert nicht gespeichert.

70voto

Emran Hussain Punkte 10644

Hier ist eine bessere gekapselte Lösung:

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

Sagen wir, das ist Ihr Modell:

enter image description here

Verwendungsbeispiel:

enter image description here

Generierte UI: enter image description here

Und generiertes HTML

enter image description here

Der Quellcode der Helper-Erweiterung als Momentaufnahme:

enter image description here

Sie können das Beispielprojekt über den von mir angegebenen Link herunterladen.

EDIT: Hier ist der Code:

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 Stimmen

Nur meine Meinung, aber ich denke, diese Antwort ist viel sauberer als die akzeptierte Antwort. Besonders gut gefällt mir die Möglichkeit, das Attribut Beschreibung zu verwenden. Ich habe den Code hinzugefügt, damit die Leute ihn ohne Herunterladen kopieren/einfügen können.

0 Stimmen

Aufruf der Erweiterungsmethode als EnumDropDownListFor statt DropDownListFor Verwendung:-> @Html.EnumDropDownListFor(x => x.Geschlecht)

0 Stimmen

Für Jemanden, der ein weiteres Element sucht "Please Select" return htmlHelper.DropDownListFor(expression, createSelectList(expression.ReturnType, selected,firstElement), "Please Select");

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X