Связать Enum с DropDownList в MVC 4?

Я обнаружил повсюду, что общий способ привязки Enums к DropDowns осуществляется через вспомогательные методы, которые кажутся немного властными для такой, казалось бы, простой задачи.

Каков наилучший способ привязки Enums к DropDownLists в ASP.Net MVC 4?

+19
24 июн. '13 в 16:57
источник поделиться
7 ответов

Я думаю, что речь идет о единственном (чистом) способе, который жаль, но, по крайней мере, есть несколько вариантов. Я бы рекомендовал посмотреть этот блог: http://paulthecyclist.com/2013/05/24/enum-dropdown/

Извините, это слишком долго, чтобы копировать здесь, но суть в том, что он создал для него новый HTML-метод.

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

+17
24 июн. '13 в 17:15
источник

Вы можете:

@Html.DropDownListFor(model => model.Type, Enum.GetNames(typeof(Rewards.Models.PropertyType)).Select(e => new SelectListItem { Text = e }))
+23
24 янв. '14 в 0:55
источник

Перечисления поддерживаются каркасом, поскольку MVC 5.1:

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

Отображаемый текст можно настроить:

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

    Colour
}

Ссылка MSDN: http://www.asp.net/mvc/overview/releases/mvc51-release-notes#Enum

+13
18 авг. '14 в 16:55
источник

В моем контроллере:

var feedTypeList = new Dictionary<short, string>();
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)
+9
05 июл. '13 в 17:07
источник

Технически вам не нужен вспомогательный метод, поскольку Html.DropdownListFor требуется только SelectList или Ienumerable<SelectListItem>. Вы можете просто превратить свои перечисления в такой вывод и подавать их таким образом.

Я использую статический библиотечный метод для преобразования перечислений в List<SelectListItem> с несколькими параметрами/параметрами:

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

    var list = new List<SelectListItem>();

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

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

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

        list.Add(selItem);
    }

    return list;
}

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


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

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

    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<SelectListItem> PaymentMethodChoices 
{ 
    get 
    { 
        var exclusions = new List<Membership.Payment.PaymentMethod> { Membership.Payment.PaymentMethod.Unknown, Membership.Payment.PaymentMethod.Reversal };
        var selected = new List<Membership.Payment.PaymentMethod> { this.SelectedPaymentMethod };
        return GetEnumsByType<Membership.Payment.PaymentMethod>(useFriendlyName: true, exclude: exclusions, eachSelected: selected); 
    }
}

Итак, вы подключаете свой View DropDownList к этому свойству Ienumerable<SelectListItem>.

+4
24 июн. '13 в 17:51
источник

Решение от PaulTheCyclist находится на месте. Но я бы не использовал RESX (мне пришлось бы добавить новый .resx файл для каждого нового enum??)

Вот мое выражение HtmlHelper:

public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TEnum>> 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<TEnum>();

    //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<SelectListItem>
        {
            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

ОБНОВЛЕНИЕ: Извините, забыли включить код для вспомогательной функции ToDescription()

/// <summary>
/// Returns Description Attribute information for an Enum value
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
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
24 июн. '13 в 17:32
источник

Расширение хелпера html для его работы хорошо работает, но если вы хотите изменить текст выпадающих значений на основе сопоставлений DisplayAttribute, вам нужно будет изменить его, аналогичное этому,

(Сделайте это pre MVC 5.1, он включен в 5.1 +)

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 = enumValues.Select(item =>
    {
        var type = item.GetType();
        var member = type.GetMember(item.ToString());
        var attribute = member[0].GetCustomAttribute<DisplayAttribute>();
        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
20 окт. '14 в 17:32
источник

Посмотрите другие вопросы по меткам или Задайте вопрос