如何在MVC视图中启用下拉列表编辑值

时间:2010-02-21 18:08:46

标签: c# entity-framework asp.net-mvc-2 c#-4.0

返回到视图的类具有来自其他表的几个枚举值:

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

在“编辑”视图中,我想要一个包含所选值的选择框 这样用户就可以更改为另一个枚举值。

我将枚举值放入ViewData:

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

如何从模型中选择值? 像这样:

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

一旦改变了如何保存更改?

2 个答案:

答案 0 :(得分:2)

我发现自己想要频繁地为枚举做下拉列表,以至于我创建了一些方便的扩展方法。他们允许我通过以下方式创建下拉列表:

这使用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());
    }
}

修改

我忘了添加将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);
        }
    }
}

答案 1 :(得分:0)

我认为你在寻找Enum.Parse:

Rank rankValue = (Rank) Enum.Parse(typeof(Rank), rankString);