MVC3 Razor DropDownListFor Enums

84

Ich versuche, mein Projekt auf MVC3 zu aktualisieren, was ich einfach nicht finden kann:

Ich habe einen einfachen Datentyp von ENUMS:

public enum States()
{
  AL,AK,AZ,...WY
}

Was ich als DropDown / SelectList in meiner Ansicht eines Modells verwenden möchte, das diesen Datentyp enthält:

public class FormModel()
{
    public States State {get; set;}
}

Ziemlich einfach: Wenn ich die automatisch generierte Ansicht für diese Teilklasse verwende, wird dieser Typ ignoriert.

Ich benötige eine einfache Auswahlliste, die den Wert der Aufzählung als ausgewähltes Element festlegt, wenn ich auf Senden und Verarbeiten über meine AJAX-JSON-POST-Methode drücke.

Und als die Aussicht (???!):

    <div class="editor-field">
        @Html.DropDownListFor(model => model.State, model => model.States)
    </div>

Vielen Dank im Voraus für den Rat!

jordan.baucke
quelle
8
Für alle, die auf diesen Thread stoßen und MVC 5.1 oder höher verwenden, ist die Hilfsmethode @ Html.EnumDropDownListFor () jetzt in MVC integriert - siehe asp.net/mvc/overview/releases/mvc51-release-notes
mecsco

Antworten:

55

Ich habe gerade eine für mein eigenes Projekt gemacht. Der folgende Code ist Teil meiner Hilfsklasse. Ich hoffe, dass ich alle erforderlichen Methoden erhalten habe. Schreiben Sie einen Kommentar, wenn es nicht funktioniert, und ich werde es erneut überprüfen.

public static class SelectExtensions
{

    public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
    {
        string inputName = GetInputName(expression);
        var value = htmlHelper.ViewData.Model == null
            ? default(TProperty)
            : expression.Compile()(htmlHelper.ViewData.Model);

        return htmlHelper.DropDownList(inputName, ToSelectList(typeof(TProperty), value.ToString()));
    }

    public static SelectList ToSelectList(Type enumType, string selectedItem)
    {
        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var item in Enum.GetValues(enumType))
        {
            FieldInfo fi = enumType.GetField(item.ToString());
            var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
            var title = attribute == null ? item.ToString() : ((DescriptionAttribute)attribute).Description;
            var listItem = new SelectListItem
                {
                    Value = ((int)item).ToString(),
                    Text = title,
                    Selected = selectedItem == ((int)item).ToString()
                };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text", selectedItem);
    }
}

Verwenden Sie es als:

Html.EnumDropDownListFor(m => m.YourEnum);

Aktualisieren

Ich habe alternative HTML-Helfer erstellt. Alles, was Sie tun müssen, um sie zu verwenden, ist, Ihre Basisansichtseite in zu ändern views\web.config.

Mit ihnen können Sie einfach tun:

@Html2.DropDownFor(m => m.YourEnum);
@Html2.CheckboxesFor(m => m.YourEnum);
@Html2.RadioButtonsFor(m => m.YourEnum);

Weitere Informationen hier: http://blog.gauffin.org/2011/10/first-draft-of-my-alternative-html-helpers/

jgauffin
quelle
1
Ok, es funktioniert so oder so, ich erhalte nur einen Kompilierungsfehler: Zeile 41: return htmlHelper.DropDownList (inputName, ToSelectList (typeof (TProperty), value.ToString ())); 'System.Web.Mvc.HtmlHelper <TModel>' enthält keine Definition für 'DropDownList' und es konnte keine Erweiterungsmethode 'DropDownList' gefunden werden, die ein erstes Argument vom Typ 'System.Web.Mvc.HtmlHelper <TModel>' akzeptiert ( Vermissen Sie eine Verwendungsrichtlinie oder eine Versammlungsreferenz?)
jordan.baucke
1
@ Jordan Ich habe den gleichen Fehler. Haben Sie es geschafft, das Problem zu beheben?
SF Entwickler
9
@filu @jordan hinzufügen, using System.Web.Mvc.Html;wie Sie benötigen, um auf dieSelectExtensionsClass
Simon Hartcher
3
@Para Ich erhalte das gleiche Problem. Der ausgewählte Wert wird in der Ansicht nicht ausgewählt angezeigt. (Ich hatte zu ändern ((int)item).ToString()für Enum.GetName(enumType, item)die erhalten SelectListItemkorrekt gespeichert , wie ausgewählt, aber es funktioniert immer noch nicht)
Fernando Neira
1
Ich habe unten eine Antwort hinzugefügt, die das Auswahlproblem abdeckt - ergibt sich aus einem Missverständnis des Verhaltens der DropDownList-Überladungen.
Jon Egerton
199

Ich habe hier eine einfachere Lösung gefunden: http://coding-in.net/asp-net-mvc-3-method-extension/

using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace EnumHtmlHelper.Helper
{    
    public static class EnumDropDownList
    {
        public static HtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression, string firstElement)
        {
            var typeOfProperty = modelExpression.ReturnType;
            if(!typeOfProperty.IsEnum)
                throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));     
            var enumValues = new SelectList(Enum.GetValues(typeOfProperty));
            return htmlHelper.DropDownListFor(modelExpression, enumValues, firstElement);
}   }   }

Eine Linie im Rasiermesser wird es tun:

@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States))))

Code dazu finden Sie auch im verlinkten Artikel.

Mike McLaughlin
quelle
6
Ich denke, dieser hätte als Lösung markiert werden sollen. Das Beste zeichnet sich nicht durch Komplexität aus, sondern durch Einfachheit.
Lord of Scripts
3
Für die Leute, die eine DropDowList-Version suchen (wie ich): @ Html.DropDownList ("listName", neue SelectList (Enum.GetValues ​​(typeof (MyNamespace.Enums.States)))
dstr
2
@ JonEgerton Wenn du das gleiche meinst wie ich, dann stimme ich zu. Wenn Sie Aufzählungen + Beschreibung + ein Bild anzeigen möchten, sind Sie mit der Lösung von Mike McLaughlin verloren.
Elisabeth
1
Das einzige Problem, das ich bei diesen Lösungen festgestellt habe, ist, dass der ausgewählte Wert beim Laden nicht richtig zugeordnet wird. Abgesehen davon ziemlich gut.
Triangulito
3
@ Triangulito das ist überhaupt kein Problem :)@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States)),model.State))
VladL
24

Ab ASP.NET MVC 5.1 (RC1) , EnumDropDownListForwird standardmäßig als eine Erweiterung des Verfahrens enthalten HtmlHelper.

Vincent Sels
quelle
17

Wenn Sie etwas wirklich Einfaches möchten, gibt es einen anderen Weg, je nachdem, wie Sie den Status in der Datenbank speichern.

Wenn Sie eine Entität wie diese hatten:

public class Address
{
     //other address fields

     //this is what the state gets stored as in the db
     public byte StateCode { get; set; }

     //this maps our db field to an enum
     public States State
     {
         get
         {
             return (States)StateCode;
         }
         set
         {
             StateCode = (byte)value;
         }
     }
}

Dann wäre das Generieren des Dropdowns so einfach:

@Html.DropDownListFor(x => x.StateCode,
    from State state in Enum.GetValues(typeof(States))
    select new SelectListItem() { Text = state.ToString(), Value = ((int)state).ToString() }
);

Ist LINQ nicht hübsch?

sjmeverett
quelle
Wo definieren Sie die Statusaufzählung im Modell oder in der Ansicht?
Superartsy
im Modell, wie es von der Modellklasse verwendet wird
sjmeverett
1
@stewartml Wenn mein ViewModel die Eigenschaft enum + "SelectedCodeProperty" hat, ist dies eine Eigenschaft zu viel in Ihrem Beitrag. Warum nicht die Aufzählung in beiden als ausgewählten Wert als Elementwert auf den Server zurückschicken lassen?
Elisabeth
13

Ich konnte dies in einem Einzeiler tun.

@Html.DropDownListFor(m=>m.YourModelProperty,new SelectList(Enum.GetValues(typeof(YourEnumType))))
JM1990
quelle
8

Basierend auf der akzeptierten Antwort von @jgauffin habe ich meine eigene Version von erstellt EnumDropDownListFor, die sich mit dem Problem der Auswahl von Elementen befasst.

Das Problem wird in einer anderen SO-Antwort hier detailliert beschrieben : und ist im Wesentlichen auf ein Missverständnis des Verhaltens der verschiedenen Überlastungen von zurückzuführen DropDownList.

Mein vollständiger Code (der Überladungen für htmlAttributesusw. enthält) lautet:

public static class EnumDropDownListForHelper
{

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

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            object htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            IDictionary<string, object> htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, optionLabel, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            IDictionary<string,object> htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            object htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }


    private static string GetInputName<TModel, TProperty>(
            Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            MethodCallExpression methodCallExpression 
                            = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString()
                    .Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression 
                            = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }


    private static SelectList ToSelectList(Type enumType)
    {
        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var item in Enum.GetValues(enumType))
        {
            FieldInfo fi = enumType.GetField(item.ToString());
            var attribute = fi.GetCustomAttributes(
                                       typeof(DescriptionAttribute), true)
                                  .FirstOrDefault();
            var title = attribute == null ? item.ToString() 
                              : ((DescriptionAttribute)attribute).Description;
            var listItem = new SelectListItem
            {
                Value = item.ToString(),
                Text = title,
            };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text");
    }
}

Ich habe das hier in meinem Blog geschrieben .

Jon Egerton
quelle
1
Dies ist die einzige Lösung, die mir begegnet ist und die den relevanten Wert für meine Aufzählung korrekt vorab auswählt. Vielen Dank!
Edwin Groenendaal
Genial. Dies sollte definitiv die akzeptierte Antwort sein - es funktioniert; die akzeptierte Antwort nicht.
Neminem
3

Dies wäre hilfreich für die Auswahl eines int-Werts aus enum: Hier SpecTypeist ein intFeld ... und enmSpecTypeein enum.

@Html.DropDownList(
    "SpecType", 
     YourNameSpace.SelectExtensions.ToSelectList(typeof(NREticaret.Core.Enums.enmSpecType), 
     Model.SpecType.ToString()), "Tip Seçiniz", new 
     { 
         gtbfieldid = "33", 
         @class = "small" 
     })
user687314
quelle
3

Ich habe die SelectList-Methode wie folgt geändert, damit sie für mich etwas besser funktioniert. Vielleicht ist es für andere nützlich.

public static SelectList ToSelectList<T>(T selectedItem)
        {
            if (!typeof(T).IsEnum) throw new InvalidEnumArgumentException("The specified type is not an enum");

            var selectedItemName = Enum.GetName(typeof (T), selectedItem);
            var items = new List<SelectListItem>();
            foreach (var item in Enum.GetValues(typeof(T)))
            {
                var fi = typeof(T).GetField(item.ToString());
                var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();

                var enumName = Enum.GetName(typeof (T), item);
                var title = attribute == null ? enumName : ((DescriptionAttribute)attribute).Description;

                var listItem = new SelectListItem
                {
                    Value = enumName,
                    Text = title,
                    Selected = selectedItemName == enumName
                };
                items.Add(listItem);
            }

            return new SelectList(items, "Value", "Text");
        }
Jason
quelle
3
    public enum EnumStates
    {
        AL = 0,
        AK = 1,
        AZ = 2,
        WY = 3
    }


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), "select", new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)  //With select



//Or


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), null, new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)   //With out select
Thulasiram
quelle
Wo definieren Sie EnumState?
Superartsy
oben kannst du es sehen ... public enum EnumStates
Thulasiram
2

Gleich wie bei Mike (der zwischen langen Antworten vergraben ist)

model.truckimagelocation ist eine Klasseninstanzeigenschaft des Aufzählungstyps TruckImageLocation

@Html.DropDownListFor(model=>model.truckimagelocation,Enum.GetNames(typeof(TruckImageLocation)).ToArray().Select(f=> new SelectListItem() {Text = f, Value = f, Selected = false}))
user794791
quelle
2

Dies ist der allgemeinste Code, der für alle Enums verwendet wird.

public static class UtilitiesClass
{

    public static SelectList GetEnumType(Type enumType)
    {
        var value = from e in Enum.GetNames(enumType)
                    select new
                    {
                        ID = Convert.ToInt32(Enum.Parse(enumType, e, true)),
                        Name = e
                    };
        return new SelectList(value, "ID", "Name");
    }
}

Aktionsmethode

ViewBag.Enum= UtilitiesClass.GetEnumType(typeof (YourEnumType));

View.cshtml

 @Html.DropDownList("Type", (IEnumerable<SelectListItem>)ViewBag.Enum, new { @class = "form-control"})
Muhammad Kamran
quelle
1

Sie können enum in Ihrem Modell verwenden

deine Aufzählung

public enum States()
{
  AL,AK,AZ,...WY
}

mach ein Modell

public class enumclass
{
public States statesprop {get; set;}
}

im Hinblick auf

@Html.Dropdownlistfor(a=>a.statesprop)
MaTya
quelle
Neueste Fragen Beantworten Sie kar.
Anup
1

Die einfachste Antwort in MVC5 lautet "Enum definieren":

public enum ReorderLevels {
          zero = 0,
            five = 5,
            ten = 10,
            fifteen = 15,
            twenty = 20,
            twenty_five = 25,
            thirty = 30
        }

In Ansicht binden:

        <div class="form-group">
            <label>Reorder Level</label>
            @Html.EnumDropDownListFor(m => m.ReorderLevel, "Choose Me", new { @class = "form-control" })
        </div>
Mark Phillips
quelle