我正在尝试使用Html。下拉列表扩展方法,但不知道如何与枚举一起使用它。

假设我有一个这样的枚举:

public enum ItemTypes
{
    Movie = 1,
    Game = 2,
    Book = 3
}

我如何去创建一个下拉与这些值使用Html。下拉列表扩展方法?

或者我最好的办法是简单地创建一个for循环并手动创建Html元素?


当前回答

这里是Martin Faartoft的变种,你可以放自定义标签,这对本地化很好。

public static class EnumHtmlHelper
{
    public static SelectList ToSelectList<TEnum>(this TEnum enumObj, Dictionary<int, string> customLabels)
        where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        var values = from TEnum e in Enum.GetValues(typeof(TEnum))
                     select new { Id = e, Name = customLabels.First(x => x.Key == Convert.ToInt32(e)).Value.ToString() };

        return new SelectList(values, "Id", "Name", enumObj);
    }
}

视图中使用:

@Html.DropDownListFor(m => m.Category, Model.Category.ToSelectList(new Dictionary<int, string>() { 
          { 1, ContactResStrings.FeedbackCategory }, 
          { 2, ContactResStrings.ComplainCategory }, 
          { 3, ContactResStrings.CommentCategory },
          { 4, ContactResStrings.OtherCategory }
      }), new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Category)

其他回答

我做了以下工作,并取得了成功:

在view.cshtml中:

@ model MyModel.cs

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

模型中: MyModel.cs

MyItemType {get;设置;}

根据Simon的回答,类似的方法是从Resource文件中获取要显示的Enum值,而不是在Enum本身的描述属性中。如果你的网站需要用多种语言呈现,如果你有一个特定的枚举资源文件,这是很有帮助的,你可以更进一步,在你的Enum中只有Enum值,并从扩展中引用它们,如[EnumName]_[EnumValue] -最终更少的输入!

然后扩展看起来像:

public static IHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> html, Expression<Func<TModel, TEnum>> expression)
{            
    var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);

    var enumType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType;

    var enumValues = Enum.GetValues(enumType).Cast<object>();

    var items = from enumValue in enumValues                        
                select new SelectListItem
                {
                    Text = GetResourceValueForEnumValue(enumValue),
                    Value = ((int)enumValue).ToString(),
                    Selected = enumValue.Equals(metadata.Model)
                };


    return html.DropDownListFor(expression, items, string.Empty, null);
}

private static string GetResourceValueForEnumValue<TEnum>(TEnum enumValue)
{
    var key = string.Format("{0}_{1}", enumValue.GetType().Name, enumValue);

    return Enums.ResourceManager.GetString(key) ?? enumValue.ToString();
}

枚举中的资源。Resx文件看起来像这样 ItemTypes_Movie:电影

我喜欢做的另一件事是,与其直接调用扩展方法,不如使用@Html调用它。EditorFor(x => x.MyProperty),或者理想情况下只有整个表单,在一个整洁的@Html.EditorForModel()中。为此,我将字符串模板更改为如下所示

@using MVCProject.Extensions

@{
    var type = Nullable.GetUnderlyingType(ViewData.ModelMetadata.ModelType) ?? ViewData.ModelMetadata.ModelType;

    @(typeof (Enum).IsAssignableFrom(type) ? Html.EnumDropDownListFor(x => x) : Html.TextBoxFor(x => x))
}

如果你对此感兴趣,我在我的博客上给出了更详细的答案:

http://paulthecyclist.com/2013/05/24/enum-dropdown/

我最终创建了扩展方法来执行这里基本上可以接受的答案。Gist的后半部分专门处理Enum。

https://gist.github.com/3813767

您希望使用类似Enum的东西。getvalue

扩展Prise和Rune的答案,如果你想让你的选择列表项的value属性映射到枚举类型的整数值,而不是字符串值,使用以下代码:

public static SelectList ToSelectList<T, TU>(T enumObj) 
    where T : struct
    where TU : struct
{
    if(!typeof(T).IsEnum) throw new ArgumentException("Enum is required.", "enumObj");

    var values = from T e in Enum.GetValues(typeof(T))
                 select new { 
                    Value = (TU)Convert.ChangeType(e, typeof(TU)),
                    Text = e.ToString() 
                 };

    return new SelectList(values, "Value", "Text", enumObj);
}

与其将每个Enumeration值视为TEnum对象,不如将其视为对象,然后将其强制转换为整数以获得未装箱的值。

注意: 我还添加了一个泛型类型约束,以限制该扩展只能用于结构(Enum的基类型)的类型,以及一个运行时类型验证,以确保传入的结构确实是Enum。

更新10/23/12: 为底层类型添加了泛型类型参数,并修复了影响. net 4+的非编译问题。