Прив'язка Enum до DropDownList у MVC 4?

Я знаходжу в усьому місці, що загальний спосіб пов'язувати Енум з DropDown використовує допоміжні методи, які здаються трохи владними для такого, здавалося б, простим завданням.

Який найкращий спосіб пов'язувати Enums з DropDownLists у ASP.Net MVC 4?

20
@ Шеридан Трохи пізно, чи не погодилися б ви?
додано Автор Roach Lord, джерело
Ні, я б зовсім не погодився. Я не міг позначити ваше запитання як дублікат, перш ніж я його бачив, чи можу я це зробити? Якщо у вас виникли певні проблеми, можливо, вам слід прочитати чому деякі запитання позначені як дублікати? сторінка довідкового центру переповнення стека замість залишення безглуздих коментарів?
додано Автор Sheridan, джерело
Ні, я б зовсім не погодився. Я не міг позначити ваше запитання як дублікат, перш ніж я його бачив, чи можу я це зробити? Якщо у вас виникли певні проблеми, можливо, вам слід прочитати чому деякі запитання позначені як дублікати? сторінка довідкового центру переповнення стека замість залишення безглуздих коментарів?
додано Автор Sheridan, джерело

10 Відповіді

Ви можете:

@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
23
додано
Дякую. Щоб включити int-значення enum, просто поширюйте його таким чином: ... {Text = e, Value = ((int) Enum.Parse (typeof (UngKlub.Web.Models.Member.GenderEnum & zwnj; ), e)). ToString ())))
додано Автор Michael Olesen, джерело
Ідеальне рішення, якщо ви хочете використовувати енну з [FLAG]
додано Автор mejiamanuel57, джерело

I think it is about the only (clean) way, which is a pity, but at least there are a few options out there. I'd recommend having a look at this blog: http://paulthecyclist.com/2013/05/24/enum-dropdown/

На жаль, занадто довго копіювати тут, але суть полягає в тому, що він створив новий допоміжний метод HTML для цього.

Весь вихідний код доступний на GitHub .

18
додано
У випадку, якщо хтось зацікавлений (я знаю, ОП визначає MVC 4) MVC 5.1 має підтримку переліку: asp.net/mvc/overview/releases/mvc51-release-notes#Enum
додано Автор Bernhard Hofmann, джерело
Підказка палтчецикліста приємно, але у нього не вистачає деталей у цьому положенні ... набагато краще йти прямо до свого гітбуба. Спасибі, хоча
додано Автор Roach Lord, джерело
Як зазначає Бернард, MVC5.1 тепер охоплює це, якщо ви можете використовувати цю версію. Я створив новий запис у блозі paulthecyclist.com/2014/04/ 03/enum-dropdown-mvc5-1 на основі мого попереднього показано один спосіб, яким ви можете скористатися цією функцією, і все одно отримувати спадні значення з файлу resx.
додано Автор PaulTheCyclist, джерело
Суть цієї відповіді відповідає у цьому питанні: stackoverflow.com/questions/388483/ … , а також багато інших рішень цієї проблеми.
додано Автор PaulTheCyclist, джерело
набагато краще рішення тут. stackoverflow.com/questions/388483/ …
додано Автор JenonD, джерело

I think it is about the only (clean) way, which is a pity, but at least there are a few options out there. I'd recommend having a look at this blog: http://paulthecyclist.com/2013/05/24/enum-dropdown/

На жаль, занадто довго копіювати тут, але суть полягає в тому, що він створив новий допоміжний метод HTML для цього.

Весь вихідний код доступний на GitHub .

18
додано
У випадку, якщо хтось зацікавлений (я знаю, ОП визначає MVC 4) MVC 5.1 має підтримку переліку: asp.net/mvc/overview/releases/mvc51-release-notes#Enum
додано Автор Bernhard Hofmann, джерело
Підказка палтчецикліста приємно, але у нього не вистачає деталей у цьому положенні ... набагато краще йти прямо до свого гітбуба. Спасибі, хоча
додано Автор Roach Lord, джерело
Як зазначає Бернард, MVC5.1 тепер охоплює це, якщо ви можете використовувати цю версію. Я створив новий запис у блозі paulthecyclist.com/2014/04/ 03/enum-dropdown-mvc5-1 на основі мого попереднього показано один спосіб, яким ви можете скористатися цією функцією, і все одно отримувати спадні значення з файлу resx.
додано Автор PaulTheCyclist, джерело
Суть цієї відповіді відповідає у цьому питанні: stackoverflow.com/questions/388483/ … , а також багато інших рішень цієї проблеми.
додано Автор PaulTheCyclist, джерело
набагато краще рішення тут. stackoverflow.com/questions/388483/ …
додано Автор JenonD, джерело

Enums підтримуються рамками, починаючи з MVC 5.1:

@Html.EnumDropDownListFor(m => m.Palette)

Відображений текст можна налаштувати:

public enum Palette
{
    [Display(Name = "Black & White")]
    BlackAndWhite,

    Colour
}

MSDN link: http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum

13
додано
ідеальний і простий у використанні :)
додано Автор Bimal Das, джерело

У моєму контролері:

var feedTypeList = new Dictionary();
foreach (var item in Enum.GetValues(typeof(FeedType)))
{
    feedTypeList.Add((short)item, Enum.GetName(typeof(FeedType), item));
}
ViewBag.FeedTypeList = new SelectList(feedTypeList, "Key", "Value", feed.FeedType);

На мій погляд:

@Html.DropDownList("FeedType", (SelectList)ViewBag.FeedTypeList)
10
додано
коли я виконую операцію редагування не вибрати bind значення в спадному меню? Будь ласка, допоможіть
додано Автор Brijesh Mavani, джерело

Рішення від PaulTheCyclist є місцем на. Але я б не використовував RESX (мені доведеться додати новий файл .resx для кожного нового переліку?)

Ось моя вираз HtmlHelper:

public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper,
    Expression> expression, object attributes = null)
{
    //Get metadata from enum
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var enumType = GetNonNullableModelType(metadata);
    var values = Enum.GetValues(enumType).Cast();

    //Convert enumeration items into SelectListItems
    var items =
        from value in values
        select new SelectListItem
        {
            Text = value.ToDescription(),
            Value = value.ToString(),
            Selected = value.Equals(metadata.Model)
        };

    //Check for nullable value types
    if (metadata.IsNullableValueType)
    {
        var emptyItem = new List
        {
            new SelectListItem {Text = string.Empty, Value = string.Empty}
        };
        items = emptyItem.Concat(items);
    }

    //Return the regular DropDownlist helper
    return htmlHelper.DropDownListFor(expression, items, attributes);
}

Ось як я оголошую свої енуми:

[Flags]
public enum LoanApplicationType
{
    [Description("Undefined")]
    Undefined = 0,

    [Description("Personal Loan")]
    PersonalLoan = 1,

    [Description("Mortgage Loan")]
    MortgageLoan = 2,

    [Description("Vehicle Loan")]
    VehicleLoan = 4,

    [Description("Small Business")]
    SmallBusiness = 8,
}

І ось виклик із зображення Razor View:

<div class="control-group span2">
    <div class="controls">
        @Html.EnumDropDownListFor(m => m.LoanType, new { @class = "span2" })
    </div>
</div>

Де @ Model.LoanType є властивістю моделі типу LoanApplicationType

UPDATE: Sorry, forgot to include code for the helper function ToDescription()

/// 
/// Returns Description Attribute information for an Enum value ///
 
/// 
/// 
public static string ToDescription(this Enum value)
{
    if (value == null)
    {
        return string.Empty;
    }
    var attributes = (DescriptionAttribute[]) value.GetType().GetField(
        Convert.ToString(value)).GetCustomAttributes(typeof (DescriptionAttribute), false);
    return attributes.Length > 0 ? attributes[0].Description : Convert.ToString(value);
}
4
додано
Я думаю, це має сенс, якщо вам потрібно локалізувати для багатьох мов. Час, коли мені довелося використовувати файл RESX, я зазвичай декорую перерахування з належним DataAnnotationAttribute і встановлюю запис файлу ресурсу безпосередньо на перерахування. Але я думаю, ваш підхід буде більш зручним. Я спробую це найближчим часом (дякую)
додано Автор amhed, джерело
Привіт, якщо б ви мали використовувати рішення на основі мого блогу, вам потрібен лише один файл для всіх файлів resumes для всіх ваших Енумів і просто використовуйте конвенцію, щоб відрізняти енуми. наприклад, якщо у вас є два псевдоніми, вказуються кольори та цифри. деякі рекшерські записи можуть містити такі назви: Colour_Blue, Colour_Red, Colour_White, LoanApplicationType_Undefined, LoanApplicationType_Personal. Опис атрибута відмінно працює, хоча, якщо ваша веб-програма не потребує розгляду локалізації
додано Автор PaulTheCyclist, джерело

Рішення від PaulTheCyclist є місцем на. Але я б не використовував RESX (мені доведеться додати новий файл .resx для кожного нового переліку?)

Ось моя вираз HtmlHelper:

public static MvcHtmlString EnumDropDownListFor(this HtmlHelper htmlHelper,
    Expression> expression, object attributes = null)
{
    //Get metadata from enum
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var enumType = GetNonNullableModelType(metadata);
    var values = Enum.GetValues(enumType).Cast();

    //Convert enumeration items into SelectListItems
    var items =
        from value in values
        select new SelectListItem
        {
            Text = value.ToDescription(),
            Value = value.ToString(),
            Selected = value.Equals(metadata.Model)
        };

    //Check for nullable value types
    if (metadata.IsNullableValueType)
    {
        var emptyItem = new List
        {
            new SelectListItem {Text = string.Empty, Value = string.Empty}
        };
        items = emptyItem.Concat(items);
    }

    //Return the regular DropDownlist helper
    return htmlHelper.DropDownListFor(expression, items, attributes);
}

Ось як я оголошую свої енуми:

[Flags]
public enum LoanApplicationType
{
    [Description("Undefined")]
    Undefined = 0,

    [Description("Personal Loan")]
    PersonalLoan = 1,

    [Description("Mortgage Loan")]
    MortgageLoan = 2,

    [Description("Vehicle Loan")]
    VehicleLoan = 4,

    [Description("Small Business")]
    SmallBusiness = 8,
}

І ось виклик із зображення Razor View:

<div class="control-group span2">
    <div class="controls">
        @Html.EnumDropDownListFor(m => m.LoanType, new { @class = "span2" })
    </div>
</div>

Де @ Model.LoanType є властивістю моделі типу LoanApplicationType

UPDATE: Sorry, forgot to include code for the helper function ToDescription()

/// 
/// Returns Description Attribute information for an Enum value ///
 
/// 
/// 
public static string ToDescription(this Enum value)
{
    if (value == null)
    {
        return string.Empty;
    }
    var attributes = (DescriptionAttribute[]) value.GetType().GetField(
        Convert.ToString(value)).GetCustomAttributes(typeof (DescriptionAttribute), false);
    return attributes.Length > 0 ? attributes[0].Description : Convert.ToString(value);
}
4
додано
Я думаю, це має сенс, якщо вам потрібно локалізувати для багатьох мов. Час, коли мені довелося використовувати файл RESX, я зазвичай декорую перерахування з належним DataAnnotationAttribute і встановлюю запис файлу ресурсу безпосередньо на перерахування. Але я думаю, ваш підхід буде більш зручним. Я спробую це найближчим часом (дякую)
додано Автор amhed, джерело
Привіт, якщо б ви мали використовувати рішення на основі мого блогу, вам потрібен лише один файл для всіх файлів resumes для всіх ваших Енумів і просто використовуйте конвенцію, щоб відрізняти енуми. наприклад, якщо у вас є два псевдоніми, вказуються кольори та цифри. деякі рекшерські записи можуть містити такі назви: Colour_Blue, Colour_Red, Colour_White, LoanApplicationType_Undefined, LoanApplicationType_Personal. Опис атрибута відмінно працює, хоча, якщо ваша веб-програма не потребує розгляду локалізації
додано Автор PaulTheCyclist, джерело

Technically, you don't need a helper method, since Html.DropdownListFor only requires a SelectList or Ienumerable. You can just turn your enums into such an output and feed it in that way.

I use a static library method to convert enums into List with a few params/options:

public static List GetEnumsByType(bool useFriendlyName = false, List exclude = null,
    List eachSelected = null, bool useIntValue = true) where T : struct, IConvertible
{
    var enumList = from enumItem in EnumUtil.GetEnumValuesFor()
                    where (exclude == null || !exclude.Contains(enumItem))
                    select enumItem;

    var list = new List();

    foreach (var item in enumList)
    {
        var selItem = new SelectListItem();

        selItem.Text = (useFriendlyName) ? item.ToFriendlyString() : item.ToString();
        selItem.Value = (useIntValue) ? item.To().ToString() : item.ToString();

        if (eachSelected != null && eachSelected.Contains(item))
            selItem.Selected = true;

        list.Add(selItem);
    }

    return list;
}

public static class EnumUtil
{
    public static IEnumerable GetEnumValuesFor()
    {
        return Enum.GetValues(typeof(T)).Cast();
    }
   //other stuff in here too...
}


/// 
/// Turns Camelcase or underscore separated phrases into properly spaces phrases /// "DogWithMustard".ToFriendlyString() == "Dog With Mustard" ///
 
public static string ToFriendlyString(this object o)
{
    var s = o.ToString();
    s = s.Replace("__", "/").Replace("_", " ");

    char[] origArray = s.ToCharArray();
    List newCharList = new List();

    for (int i = 0; i < origArray.Count(); i++)
    {
        if (origArray[i].ToString() == origArray[i].ToString().ToUpper())
        {
            newCharList.Add(' ');
        }
        newCharList.Add(origArray[i]);
    }

    s = new string(newCharList.ToArray()).TrimStart();
    return s;
}

Ваш ViewModel може передати потрібні параметри. Ось досить складний:

public IEnumerable PaymentMethodChoices 
{ 
    get 
    { 
        var exclusions = new List { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal };
        var selected = new List { this.SelectedPaymentMethod };
        return GetEnumsByType(useFriendlyName: true, exclude: exclusions, eachSelected: selected); 
    }
}

So you wire your View's DropDownList against that IEnumerable property.

4
додано

Technically, you don't need a helper method, since Html.DropdownListFor only requires a SelectList or Ienumerable. You can just turn your enums into such an output and feed it in that way.

I use a static library method to convert enums into List with a few params/options:

public static List GetEnumsByType(bool useFriendlyName = false, List exclude = null,
    List eachSelected = null, bool useIntValue = true) where T : struct, IConvertible
{
    var enumList = from enumItem in EnumUtil.GetEnumValuesFor()
                    where (exclude == null || !exclude.Contains(enumItem))
                    select enumItem;

    var list = new List();

    foreach (var item in enumList)
    {
        var selItem = new SelectListItem();

        selItem.Text = (useFriendlyName) ? item.ToFriendlyString() : item.ToString();
        selItem.Value = (useIntValue) ? item.To().ToString() : item.ToString();

        if (eachSelected != null && eachSelected.Contains(item))
            selItem.Selected = true;

        list.Add(selItem);
    }

    return list;
}

public static class EnumUtil
{
    public static IEnumerable GetEnumValuesFor()
    {
        return Enum.GetValues(typeof(T)).Cast();
    }
   //other stuff in here too...
}


/// 
/// Turns Camelcase or underscore separated phrases into properly spaces phrases /// "DogWithMustard".ToFriendlyString() == "Dog With Mustard" ///
 
public static string ToFriendlyString(this object o)
{
    var s = o.ToString();
    s = s.Replace("__", "/").Replace("_", " ");

    char[] origArray = s.ToCharArray();
    List newCharList = new List();

    for (int i = 0; i < origArray.Count(); i++)
    {
        if (origArray[i].ToString() == origArray[i].ToString().ToUpper())
        {
            newCharList.Add(' ');
        }
        newCharList.Add(origArray[i]);
    }

    s = new string(newCharList.ToArray()).TrimStart();
    return s;
}

Ваш ViewModel може передати потрібні параметри. Ось досить складний:

public IEnumerable PaymentMethodChoices 
{ 
    get 
    { 
        var exclusions = new List { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal };
        var selected = new List { this.SelectedPaymentMethod };
        return GetEnumsByType(useFriendlyName: true, exclude: exclusions, eachSelected: selected); 
    }
}

So you wire your View's DropDownList against that IEnumerable property.

4
додано

Продовження HTML-помічника для цього робить це добре, але якщо ви хочете змінити текст випадаючого значення на основі відображень DisplayAttribute, то вам потрібно буде змінити його, подібно цьому,

(Зробіть це перед MVC 5.1, він включений в 5.1+)

public static IHtmlString EnumDropDownListFor(this HtmlHelper html, Expression> expression)
{
    var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;
    var enumValues = Enum.GetValues(enumType).Cast();
    var items = enumValues.Select(item =>
    {
        var type = item.GetType();
        var member = type.GetMember(item.ToString());
        var attribute = member[0].GetCustomAttribute(); string text = attribute != null ? ((DisplayAttribute)attribute).Name : item.ToString(); string value = ((int)item).ToString(); bool selected = item.Equals(metadata.Model); return new SelectListItem { Text = text, Value = value, Selected = selected }; }); return html.DropDownListFor(expression, items, string.Empty, null); } 
0
додано
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug