MVC3 EnumDropdownList выбранное значение - PullRequest
2 голосов
/ 14 февраля 2012

Есть несколько полезных методов расширения для использования отображения перечислений в выпадающих списках. Например, здесь и здесь .

Но есть одна проблема, с которой я сталкиваюсь, это то, что эти помощники не работают, если enum украшен атрибутом Description. Первый пример прекрасно работает с атрибутом Description, но не устанавливает выбранное значение. Второй пример устанавливает выбранное значение, но он не использует атрибут описания. Поэтому мне нужно объединить оба метода в рабочий помощник, который делает оба правильно. У меня много вариантов, чтобы заставить его работать, но пока безуспешно. Я пробовал несколько способов создать список выбора, но каким-то образом он игнорирует свойство Selected. Во всех моих тестах свойство Selected было установлено в true для одного элемента, но это свойство просто игнорируется. Поэтому любые идеи приветствуются!

Это последний код, который я пробовал:

public static IEnumerable<SelectListItem> 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 == item.ToString()
            };

            items.Add(listItem);
        }
        return items;

    }

public static HtmlString EnumDropDownList2For<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression)
    {
        var typeOfProperty = modelExpression.ReturnType;
        if (!typeOfProperty.IsEnum)
            throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));

        var value = htmlHelper.ViewData.Model == null
            ? default(TProperty)
            : modelExpression.Compile()(htmlHelper.ViewData.Model);

        return htmlHelper.DropDownListFor(modelExpression, ToSelectList(modelExpression.ReturnType, value.ToString()));
    }

Ответы [ 2 ]

3 голосов
/ 24 февраля 2012

У меня была такая же проблема с перечислениями, для которых фактически было установлено пользовательское значение

public enum Occupation
{
    [Description("Lorry driver")] LorryDriver = 10,
    [Description("The big boss")] Director = 11,
    [Description("Assistant manager")] AssistantManager = 12
}

Я обнаружил, что при использовании DropDownListFor () он не использует выбранный элемент из коллекции SelectListItem для установки выбранного параметра. Вместо этого он выбирает параметр со значением, равным свойству, с которым я пытаюсь связать (m => m.Occupation), и для этого он использует .ToString () перечисления, а не фактическое целочисленное значение перечисления. Итак, в итоге я установил значение SelectListItem следующим образом:

var listItem = new SelectListItem
{
    Value = item.ToString(), // use item.ToString() instead
    Text = title,
    Selected = selectedItem == item.ToString() // <- no need for this
};

Вспомогательный метод:

public static class SelectListItemsForHelper
{
    public static IEnumerable<SelectListItem> SelectListItemsFor<T>(T selected) where T : struct
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            return Enum.GetValues(t).Cast<Enum>().Select(e => new SelectListItem { Value = e.ToString(), Text = e.GetDescription() });
        }
        return null;
    }

    public static string GetDescription<TEnum>(this TEnum value)
    {
        FieldInfo 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();
    }
}

По виду:

@Html.DropDownListFor(m => m.Occupation, SelectListItemsForHelper.SelectListItemsFor(Model.Occupation), String.Empty)
1 голос
/ 27 февраля 2012

Подводя итог решения, которое работает (по крайней мере для меня):

Я использую следующий набор вспомогательных методов

public static IEnumerable<SelectListItem> ToSelectList(Type enumType, string selectedItem)
    {
        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var item in Enum.GetValues(enumType))
        {
            var title = item.GetDescription();
            var listItem = new SelectListItem
            {
                Value = item.ToString(),
                Text = title,
                Selected = selectedItem == item.ToString()
            };

            items.Add(listItem);
        }
        return items;

    }

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 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)
    {
        MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

Использование:

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

Это работает для перечислений с атрибутом описания или без него и устанавливает правильное выбранное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...