【问题标题】:How to enable dropdownlist editing of values in an MVC View如何在 MVC 视图中启用下拉列表编辑值
【发布时间】:2010-02-21 18:08:46
【问题描述】:

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

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

在“编辑”视图中,我希望有一个带有所选值的选择框 因此用户可以更改为另一个枚举值。

我将枚举值放入 ViewData:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • model.MyProperty) %> 太棒了!非常感谢雅各布。我仍然需要完成某些领域的学习才能理解它。我想知道为什么他们没有制作所有的 'Form'For 元素。这很酷。
    • 嗨,我忘了提到我使用的框架 4.0 不支持泛型类型上的 .Foreach 操作。您将如何替换它?
    • 另一种扩展方法。我会将其添加到答案的底部。
    【解决方案2】:

    我认为您正在寻找 Enum.Parse:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-01
      • 1970-01-01
      • 2015-08-28
      • 2013-06-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      相关资源
      最近更新 更多