Как включить редактирование выпадающего списка значений в MVC View - PullRequest
1 голос
/ 21 февраля 2010

Класс, возвращаемый в представление, имеет несколько значений перечисления из других таблиц:

class Person{
int id;
enum Rank;
enum Status;
}

В «редактируемом» представлении я хотел бы иметь поле выбора с выбранным значением таким образом, пользователь может изменить другое значение перечисления.

Я получаю значения перечисления в ViewData:

<%= Html.DropDownList("Rank")%>

как вы можете выбрать значение из модели? Вот так:

<%= Html.DropDownList("Rank", item.Rank)%>

А однажды изменилось, как сохранить изменения?

Ответы [ 2 ]

2 голосов
/ 21 февраля 2010

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

При этом используется шаблон метода расширения FooFor HtmlHelper для создания строго типизированного раскрывающегося списка:

<%= Html.EnumDropdownFor(model => model.MyProperty) %>

Вот несколько менее типизированных версий:

<%= Html.EnumDropdown("MyProperty", MyEnum.AValue /* selected value */ ) %>

<%= Html.EnumDropdown(
        "MyProperty", 
        new MyEnum[] { MyEnum.AValue, MyEnum.BValue } /* choices */ ) %>

<%= Html.EnumDropdown(
        "MyProperty",
        MyEnum.AValue                                 /* selected value */,
        new MyEnum[] { MyEnum.AValue, MyEnum.BValue } /* choices        */ ) %>

В моей реализации я также создал собственный атрибут с именем EnumDisplayNameAttribute, чтобы назначать симпатичные имена значениям перечисления, если результат по умолчанию ToString не приемлем. Вот методы расширения и вспомогательные классы, которые я написал для поддержки всего этого:

public class EnumDisplayNameAttribute : Attribute
{
    public EnumDisplayNameAttribute(string name)
    {
        this.DisplayName = name;
    }

    public string DisplayName { get; private set; }
}

public static class EnumUtils
{
    private static Dictionary<Type, IDictionary<object, string>> _nameLookups = 
        new Dictionary<Type, IDictionary<object, string>>();

    public static string GetDisplayName<T>(this T value)
    {
        var type = typeof(T);
        if (!_nameLookups.ContainsKey(type))
        {
            _nameLookups[typeof(T)] = GetEnumFields<T>()
                .ToDictionary(
                    f => f.GetValue(null),
                    f => f.GetCustomAttributes(typeof(EnumDisplayNameAttribute), true)
                            .OfType<EnumDisplayNameAttribute>()
                            .Select(a => a.DisplayName)
                            .FirstOrDefault() 
                        ?? f.Name);
        }
        return _nameLookups[type][value];
    }

    public static IEnumerable<FieldInfo> GetEnumFields<T>()
    {
        return typeof(T)
            .GetFields(BindingFlags.Public | BindingFlags.Static)
            .OfType<FieldInfo>();
    }

    public static IEnumerable<T> GetEnumValues<T>()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }
}

public static class HtmlHelperExtensions
{
    public static MvcHtmlString EnumDropdownFor<TModel, TValue>(
        this HtmlHelper<TModel> helper, 
        Expression<Func<TModel, TValue>> expression)
    {
        var data = expression.Compile()(helper.ViewData.Model);
        StringBuilder builder = new StringBuilder();
        builder.AppendFormat(
            "<select name='{0}' id='{0}'>", 
            helper.Encode(
                (expression.Body as MemberExpression).Member.Name));
        EnumUtils.GetEnumFields<TValue>()
            .ForEach(f => {
                var nameAttrib = f
                    .GetCustomAttributes(
                        typeof(EnumDisplayNameAttribute), true)
                    .OfType<EnumDisplayNameAttribute>().FirstOrDefault();
                var displayName = (nameAttrib == null)
                    ? f.Name : nameAttrib.DisplayName;

                var optionData = (TValue)f.GetRawConstantValue();
                builder.AppendFormat(
                    "<option value=\"{0}\" {1}>{2}</option>",
                    optionData, 
                    optionData.Equals(data) ? "selected=\"selected\"" : "",
                    displayName);
            }
        );
        builder.Append("</select>");
        return MvcHtmlString.Create(builder.ToString());
    }

    public static MvcHtmlString EnumDropdown<TModel, TValue>(
        this HtmlHelper<TModel> helper, string name, TValue value)
    {
        return helper.EnumDropdown(
            name, value, EnumUtils.GetEnumValues<TValue>());
    }

    public static MvcHtmlString EnumDropdown<TModel, TValue>(
        this HtmlHelper<TModel> helper, string name, 
        IEnumerable<TValue> choices)
    {
        return helper.EnumDropdown(name, choices.FirstOrDefault(), choices);
    }

    public static MvcHtmlString EnumDropdown<TModel, TValue>(
        this HtmlHelper<TModel> helper, string name, TValue value,
        IEnumerable<TValue> choices)
    {
        StringBuilder builder = new StringBuilder();
        builder.AppendFormat("<select name='{0}'>", helper.Encode(name));
        if (choices != null)
        {
            choices.ForEach(
                c => builder.AppendFormat(
                    "<option value=\"{0}\"{2}>{1}</option>",
                    Convert.ToInt32(c),
                    helper.Encode(EnumUtils.GetDisplayName(c)),
                    value.Equals(c) ? " selected='selected'" : ""));
        }
        builder.Append("</select>");
        return MvcHtmlString.Create(builder.ToString());
    }
}

Edit:

Я забыл включить метод расширения, который добавляет ForEach к IEnumerable:

public static class CollectionUtils
{
    public static void ForEach<T>(
        this IEnumerable<T> collection, Action<T> action)
    {
        foreach (var item in collection)
        {
            action(item);
        }
    }
}
0 голосов
/ 21 февраля 2010

Я думаю, что вы ищете Enum.Parse:

Rank rankValue = (Rank) Enum.Parse(typeof(Rank), rankString);       
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...