我正在尝试使用Html。下拉列表扩展方法,但不知道如何与枚举一起使用它。
假设我有一个这样的枚举:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
我如何去创建一个下拉与这些值使用Html。下拉列表扩展方法?
或者我最好的办法是简单地创建一个for循环并手动创建Html元素?
我正在尝试使用Html。下拉列表扩展方法,但不知道如何与枚举一起使用它。
假设我有一个这样的枚举:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
我如何去创建一个下拉与这些值使用Html。下拉列表扩展方法?
或者我最好的办法是简单地创建一个for循环并手动创建Html元素?
当前回答
我知道我在这方面已经晚了,但我认为您可能会发现这个变体很有用,因为它还允许您在下拉列表中使用描述性字符串而不是枚举常量。为此,使用[System.ComponentModel]装饰每个枚举条目。描述]属性。
例如:
public enum TestEnum
{
[Description("Full test")]
FullTest,
[Description("Incomplete or partial test")]
PartialTest,
[Description("No test performed")]
None
}
这是我的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Reflection;
using System.ComponentModel;
using System.Linq.Expressions;
...
private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
{
Type realModelType = modelMetadata.ModelType;
Type underlyingType = Nullable.GetUnderlyingType(realModelType);
if (underlyingType != null)
{
realModelType = underlyingType;
}
return realModelType;
}
private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };
public static string GetEnumDescription<TEnum>(TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ((attributes != null) && (attributes.Length > 0))
return attributes[0].Description;
else
return value.ToString();
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
return EnumDropDownListFor(htmlHelper, expression, null);
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
items = SingleEmptyItem.Concat(items);
return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}
然后你可以在视图中这样做:
@Html.EnumDropDownListFor(model => model.MyEnumProperty)
**编辑2014年1月23日:微软刚刚发布了MVC 5.1,现在有一个EnumDropDownListFor功能。不幸的是,它似乎不尊重[Description]属性,所以上面的代码仍然有效。请参阅微软MVC 5.1发布说明中的Enum部分。
更新:它支持显示属性[Display(Name = "Sample")],所以你可以使用它。
[更新-刚刚注意到这一点,代码看起来像一个扩展版本的代码:https://blogs.msdn.microsoft.com/stuartleeks/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums/,增加了一些内容。如果是这样,归因似乎是公平的;-)]
其他回答
我找到的最好的解决办法就是把这个博客和西蒙·戈德斯通的答案结合起来。
这允许在模型中使用枚举。从本质上讲,这个想法是使用整数属性和枚举,并模拟整数属性。
然后使用[System.ComponentModel。属性用于用你的显示文本注释模型,并在你的视图中使用“EnumDropDownListFor”扩展。
这使得视图和模型都非常可读和可维护。
模型:
public enum YesPartialNoEnum
{
[Description("Yes")]
Yes,
[Description("Still undecided")]
Partial,
[Description("No")]
No
}
//........
[Display(Name = "The label for my dropdown list")]
public virtual Nullable<YesPartialNoEnum> CuriousQuestion{ get; set; }
public virtual Nullable<int> CuriousQuestionId
{
get { return (Nullable<int>)CuriousQuestion; }
set { CuriousQuestion = (Nullable<YesPartialNoEnum>)value; }
}
观点:
@using MyProject.Extensions
{
//...
@Html.EnumDropDownListFor(model => model.CuriousQuestion)
//...
}
扩展(直接来自Simon Goldstone的回答,为完整起见,此处包含):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel;
using System.Reflection;
using System.Linq.Expressions;
using System.Web.Mvc.Html;
namespace MyProject.Extensions
{
//Extension methods must be defined in a static class
public static class MvcExtensions
{
private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
{
Type realModelType = modelMetadata.ModelType;
Type underlyingType = Nullable.GetUnderlyingType(realModelType);
if (underlyingType != null)
{
realModelType = underlyingType;
}
return realModelType;
}
private static readonly SelectListItem[] SingleEmptyItem = new[] { new SelectListItem { Text = "", Value = "" } };
public static string GetEnumDescription<TEnum>(TEnum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if ((attributes != null) && (attributes.Length > 0))
return attributes[0].Description;
else
return value.ToString();
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
return EnumDropDownListFor(htmlHelper, expression, null);
}
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = from value in values
select new SelectListItem
{
Text = GetEnumDescription(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
};
// If the enum is nullable, add an 'empty' item to the collection
if (metadata.IsNullableValueType)
items = SingleEmptyItem.Concat(items);
return htmlHelper.DropDownListFor(expression, items, htmlAttributes);
}
}
}
谢谢你的解决方案,它可以完美地应用在我的情况。唯一的问题是我必须把它翻译成VB。但现在已经完成了,为了节省其他人的时间(以防他们需要),我把它放在这里:
Imports System.Runtime.CompilerServices
Imports System.ComponentModel
Imports System.Linq.Expressions
Public Module HtmlHelpers
Private Function GetNonNullableModelType(modelMetadata As ModelMetadata) As Type
Dim realModelType = modelMetadata.ModelType
Dim underlyingType = Nullable.GetUnderlyingType(realModelType)
If Not underlyingType Is Nothing Then
realModelType = underlyingType
End If
Return realModelType
End Function
Private ReadOnly SingleEmptyItem() As SelectListItem = {New SelectListItem() With {.Text = "", .Value = ""}}
Private Function GetEnumDescription(Of TEnum)(value As TEnum) As String
Dim fi = value.GetType().GetField(value.ToString())
Dim attributes = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If Not attributes Is Nothing AndAlso attributes.Length > 0 Then
Return attributes(0).Description
Else
Return value.ToString()
End If
End Function
<Extension()>
Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum))) As MvcHtmlString
Return EnumDropDownListFor(htmlHelper, expression, Nothing)
End Function
<Extension()>
Public Function EnumDropDownListFor(Of TModel, TEnum)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TEnum)), htmlAttributes As Object) As MvcHtmlString
Dim metaData As ModelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
Dim enumType As Type = GetNonNullableModelType(metaData)
Dim values As IEnumerable(Of TEnum) = [Enum].GetValues(enumType).Cast(Of TEnum)()
Dim items As IEnumerable(Of SelectListItem) = From value In values
Select New SelectListItem With
{
.Text = GetEnumDescription(value),
.Value = value.ToString(),
.Selected = value.Equals(metaData.Model)
}
' If the enum is nullable, add an 'empty' item to the collection
If metaData.IsNullableValueType Then
items = SingleEmptyItem.Concat(items)
End If
Return htmlHelper.DropDownListFor(expression, items, htmlAttributes)
End Function
End Module
你可以这样使用它:
@Html.EnumDropDownListFor(Function(model) (model.EnumField))
我遇到了同样的问题,发现了这个问题,并认为Ash提供的解决方案不是我要寻找的;与内置的HTML . dropdownlist()函数相比,必须自己创建HTML意味着更少的灵活性。
c# 3等使得这非常简单。我有一个名为TaskStatus的枚举:
var statuses = from TaskStatus s in Enum.GetValues(typeof(TaskStatus))
select new { ID = s, Name = s.ToString() };
ViewData["taskStatus"] = new SelectList(statuses, "ID", "Name", task.Status);
这将创建一个很好的ol' SelectList,可以像在视图中一样使用:
<td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr>
匿名类型和LINQ使它更加优雅。无意冒犯,阿什。:)
我在这里找到了答案。然而,我的一些枚举有[Description(…)]属性,所以我修改了代码来提供支持:
enum Abc
{
[Description("Cba")]
Abc,
Def
}
public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, TEnum selectedValue)
{
IEnumerable<TEnum> values = Enum.GetValues(typeof(TEnum))
.Cast<TEnum>();
List<SelectListItem> items = new List<SelectListItem>();
foreach (var value in values)
{
string text = value.ToString();
var member = typeof(TEnum).GetMember(value.ToString());
if (member.Count() > 0)
{
var customAttributes = member[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (customAttributes.Count() > 0)
{
text = ((DescriptionAttribute)customAttributes[0]).Description;
}
}
items.Add(new SelectListItem
{
Text = text,
Value = value.ToString(),
Selected = (value.Equals(selectedValue))
});
}
return htmlHelper.DropDownList(
name,
items
);
}
希望这能有所帮助。
这是符文和价格的答案改变使用Enum int值作为ID。
示例枚举:
public enum ItemTypes
{
Movie = 1,
Game = 2,
Book = 3
}
扩展方法:
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
var values = from TEnum e in Enum.GetValues(typeof(TEnum))
select new { Id = (int)Enum.Parse(typeof(TEnum), e.ToString()), Name = e.ToString() };
return new SelectList(values, "Id", "Name", (int)Enum.Parse(typeof(TEnum), enumObj.ToString()));
}
用法示例:
<%= Html.DropDownList("MyEnumList", ItemTypes.Game.ToSelectList()) %>
记住导入包含Extension方法的命名空间
<%@ Import Namespace="MyNamespace.LocationOfExtensionMethod" %>
生成的HTML示例:
<select id="MyEnumList" name="MyEnumList">
<option value="1">Movie</option>
<option selected="selected" value="2">Game</option>
<option value="3">Book </option>
</select>
请注意,用于调用ToSelectList的项就是选中的项。