MVC3 Razor DropDownListFor枚举


84

试图将我的项目更新为MVC3,但我却找不到:

我有一个简单的ENUMS数据类型:

public enum States()
{
  AL,AK,AZ,...WY
}

我想在包含此数据类型的模型视图中用作DropDown / SelectList:

public class FormModel()
{
    public States State {get; set;}
}

非常简单:当我使用自动生成的视图用于此局部类时,它将忽略此类型。

我需要一个简单的选择列表,当我通过AJAX-JSON POST方法单击提交并进行处理时,将枚举的值设置为选定项。

并且比视图(???!):

    <div class="editor-field">
        @Html.DropDownListFor(model => model.State, model => model.States)
    </div>

预先感谢您的建议!


8
对于遇到此线程并使用MVC 5.1或更高版本的任何人,现在MVC都内置了辅助方法@ Html.EnumDropDownListFor()-请参阅asp.net/mvc/overview/releases/mvc51-release-notes
mecsco

Answers:


55

我刚刚为自己的项目制作了一个。下面的代码是我的帮助器类的一部分,我希望我得到了所有需要的方法。如果它不起作用,请写一条评论,我会再次检查。

public static class SelectExtensions
{

    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)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

    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 SelectList 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 == ((int)item).ToString()
                };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text", selectedItem);
    }
}

用作:

Html.EnumDropDownListFor(m => m.YourEnum);

更新资料

我创建了替代HTML助手。使用它们所需要做的就是在中更改baseviewpage views\web.config

有了他们,您可以做:

@Html2.DropDownFor(m => m.YourEnum);
@Html2.CheckboxesFor(m => m.YourEnum);
@Html2.RadioButtonsFor(m => m.YourEnum);

此处提供更多信息:http : //blog.gauffin.org/2011/10/first-draft-of-my-alternative-html-helpers/


1
好的无论哪种方式都可以,我只是遇到一个编译错误:第41行:return htmlHelper.DropDownList(inputName,ToSelectList(typeof(TProperty),value.ToString())); 'System.Web.Mvc.HtmlHelper <TModel>'不包含'DropDownList'的定义,并且找不到扩展方法'DropDownList'接受类型为'System.Web.Mvc.HtmlHelper <TModel>'的第一个参数(您是否缺少using指令或程序集引用?)
jordan.baucke

1
@jordan我有同样的错误。您是否能够解决问题?
SF开发人员

9
@filu @jordan添加using System.Web.Mvc.Html;,您需要访问SelectExtensionsClass
Simon Hartcher

3
@Para我遇到了同样的问题,所选值未在视图中显示为选中状态。(我不得不改变((int)item).ToString()Enum.GetName(enumType, item)以获得SelectListItem正确保存的选择,但它仍然无法正常工作)
费尔南多·内拉

1
刚刚在下面添加了一个覆盖选择问题的答案-源自对DropDownList重载行为的误解。
乔恩·埃格顿

199

我在这里找到了一种更简单的解决方案:http : //coding-in.net/asp-net-mvc-3-method-extension/

using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace EnumHtmlHelper.Helper
{    
    public static class EnumDropDownList
    {
        public static HtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression, string firstElement)
        {
            var typeOfProperty = modelExpression.ReturnType;
            if(!typeOfProperty.IsEnum)
                throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));     
            var enumValues = new SelectList(Enum.GetValues(typeOfProperty));
            return htmlHelper.DropDownListFor(modelExpression, enumValues, firstElement);
}   }   }

剃刀中的一行可以做到:

@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States))))

您还可以在链接的文章中找到使用扩展方法执行此操作的代码。


6
我认为这应该被标记为解决方案。最好的不是复杂性而是简单性。
剧本之王

3
对于使用DropDowList版本的用户(例如我):@ Html.DropDownList(“ listName”,new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States)))))
dstr 2012年

2
@JonEgerton如果您的意思与我相同,那么我同意。如果要显示枚举+描述+图像,那么Mike McLaughlin的解决方案会让您迷失方向。
伊丽莎白

1
我发现此解决方案的唯一问题是,在加载所选值时无法正确映射所选值。除此之外,还不错。
triangulito

3
@triangulito这根本不是问题:)@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States)),model.State))
VladL


17

如果您想要真正简单的东西,那么还有另一种方法,这取决于您在数据库中存储状态的方式。

如果您拥有这样的实体:

public class Address
{
     //other address fields

     //this is what the state gets stored as in the db
     public byte StateCode { get; set; }

     //this maps our db field to an enum
     public States State
     {
         get
         {
             return (States)StateCode;
         }
         set
         {
             StateCode = (byte)value;
         }
     }
}

然后生成下拉列表将像这样简单:

@Html.DropDownListFor(x => x.StateCode,
    from State state in Enum.GetValues(typeof(States))
    select new SelectListItem() { Text = state.ToString(), Value = ((int)state).ToString() }
);

LINQ不漂亮吗?


您在哪里定义模型或视图中的状态?
superartsy 2012年

在模型中使用,如模型类所使用
sjmeverett

1
@stewartml当我的ViewModel具有枚举属性+“ SelectedCodeProperty”时,这是您帖子中过多的一个属性。为什么不将两个枚举都作为选定值发回服务器+作为项目值。
伊丽莎白

13

我能够一口气做到这一点。

@Html.DropDownListFor(m=>m.YourModelProperty,new SelectList(Enum.GetValues(typeof(YourEnumType))))

8

根据@jgauffin接受的答案,我创建了自己的版本EnumDropDownListFor,该版本处理选择项目的问题。

该问题在此处的另一个SO答案中进行了详细说明:,基本上可以归结为对的不同重载行为的误解DropDownList

我的完整代码(包括htmlAttributesetc的重载是:

public static class EnumDropDownListForHelper
{

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            object htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            IDictionary<string, object> htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, optionLabel, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            IDictionary<string,object> htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            object htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }


    private 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)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression 
                            = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }


    private static SelectList ToSelectList(Type enumType)
    {
        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 = item.ToString(),
                Text = title,
            };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text");
    }
}

我已经在这里的博客上写了这个。


1
这是我遇到的唯一能够正确为枚举正确选择相关值的解决方案。谢谢!
Edwin Groenendaal

太棒了 这绝对应该是公认的答案-有效;公认的答案不是。
neminem 2014年

3

这将有助于从枚举中选择一个int值:这SpecType是一个int字段...,enmSpecType是一个enum

@Html.DropDownList(
    "SpecType", 
     YourNameSpace.SelectExtensions.ToSelectList(typeof(NREticaret.Core.Enums.enmSpecType), 
     Model.SpecType.ToString()), "Tip Seçiniz", new 
     { 
         gtbfieldid = "33", 
         @class = "small" 
     })

3

我对SelectList方法进行了以下更改,以使其对我来说更好一些。也许对其他人有用。

public static SelectList ToSelectList<T>(T selectedItem)
        {
            if (!typeof(T).IsEnum) throw new InvalidEnumArgumentException("The specified type is not an enum");

            var selectedItemName = Enum.GetName(typeof (T), selectedItem);
            var items = new List<SelectListItem>();
            foreach (var item in Enum.GetValues(typeof(T)))
            {
                var fi = typeof(T).GetField(item.ToString());
                var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();

                var enumName = Enum.GetName(typeof (T), item);
                var title = attribute == null ? enumName : ((DescriptionAttribute)attribute).Description;

                var listItem = new SelectListItem
                {
                    Value = enumName,
                    Text = title,
                    Selected = selectedItemName == enumName
                };
                items.Add(listItem);
            }

            return new SelectList(items, "Value", "Text");
        }

3
    public enum EnumStates
    {
        AL = 0,
        AK = 1,
        AZ = 2,
        WY = 3
    }


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), "select", new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)  //With select



//Or


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), null, new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)   //With out select

您在哪里定义EnumState?
superartsy 2012年

在顶部您可以看到它……公共枚举EnumStates
Thulasiram

2

与Mike的相同(埋在冗长的回复之间)

model.truckimagelocation是TruckImageLocation枚举类型的类实例属性

@Html.DropDownListFor(model=>model.truckimagelocation,Enum.GetNames(typeof(TruckImageLocation)).ToArray().Select(f=> new SelectListItem() {Text = f, Value = f, Selected = false}))

2

这是最通用的代码,将用于所有枚举。

public static class UtilitiesClass
{

    public static SelectList GetEnumType(Type enumType)
    {
        var value = from e in Enum.GetNames(enumType)
                    select new
                    {
                        ID = Convert.ToInt32(Enum.Parse(enumType, e, true)),
                        Name = e
                    };
        return new SelectList(value, "ID", "Name");
    }
}

行动方法

ViewBag.Enum= UtilitiesClass.GetEnumType(typeof (YourEnumType));

View.cshtml

 @Html.DropDownList("Type", (IEnumerable<SelectListItem>)ViewBag.Enum, new { @class = "form-control"})

1

您可以在模型中使用枚举

你的枚举

public enum States()
{
  AL,AK,AZ,...WY
}

做模特

public class enumclass
{
public States statesprop {get; set;}
}

鉴于

@Html.Dropdownlistfor(a=>a.statesprop)

最新问题回答kar。
Anup 2014年

1

MVC5中最简单的答案是定义枚举:

public enum ReorderLevels {
          zero = 0,
            five = 5,
            ten = 10,
            fifteen = 15,
            twenty = 20,
            twenty_five = 25,
            thirty = 30
        }

绑定视图:

        <div class="form-group">
            <label>Reorder Level</label>
            @Html.EnumDropDownListFor(m => m.ReorderLevel, "Choose Me", new { @class = "form-control" })
        </div>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.