如何在ASP.NET MVC中使用带有DescriptionAttribute的枚举

19

我对asp.net MVC还是个新手。我在尝试在我的视图页面上使用下拉控件,它从枚举中填充。我还想在下拉列表值中添加自定义描述。我搜索了很多示例,但没有人发布如何在视图页面上填充描述的帖子。以下是我的代码:

ViewModel:

public enum SearchBy
    {
        [Description("SID/PID")]
        SID = 1,
        [Description("Name")]
        Name,
        [Description("Birth Date")]
        DOB,
        [Description("Cause#")]
        Cause
    }

Index.cshtml

<div class="form-horizontal">
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group form-inline">
        @Html.LabelFor(model => model.searchBy, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EnumDropDownListFor(model => model.searchBy, "Search By", htmlAttributes: new { @class = "form-control" })
            @Html.TextBox("searchByVal", null, htmlAttributes: new { @placeholder = "SID / PID ", @class = "form-control" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @placeholder = "First Name", @class = "form-control" } })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @placeholder = "Last Name", @class = "form-control" } })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.DOB, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.DOB, new { htmlAttributes = new { @placeholder = "Birth Date", @class = "form-control" } })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.CauseNumber, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.CauseNumber, new { htmlAttributes = new { @placeholder = "Cause#", @class = "form-control" } })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Search" class="btn btn-block btn-primary" />
        </div>
    </div>
</div>
它没有像我的SearchBy枚举中提到的那样填充说明字段。在此处查看图像。 http://postimg.org/image/phdxgocj7/ 请帮助我,我错在哪里。谢谢
更新: 我从Nico那里得到了解决方案。我对此进行了一些研究。我正在使用解决方案更新此帖子,因为它可能对新手有用MVC。 http://weblogs.asp.net/jongalloway//looking-at-asp-net-mvc-5-1-and-web-api-2-1-part-1-overview-and-enums 谢谢大家。享受编码..

MVC-4中没有EnumDropDownListFor()方法。你是指MVC-5还是这是一个自定义帮助程序? - user3559349
抱歉,我更新了标签。是的,我正在使用MVC-5。 - Santosh_Sams
4个回答

30

Html助手EnumDropDownListForEnumDropDownList没有考虑到enum成员上的Description属性装饰,但是通过查看源代码:

Enum下拉列表助手: https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/SelectExtensions.cs

Enum助手类: https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/EnumHelper.cs

上面的枚举助手类用于将Enum转换为List<SelectListItem>。从下面的代码中可以看出:

// Return non-empty name specified in a [Display] attribute for the given field, if any; field's name otherwise
private static string GetDisplayName(FieldInfo field)
{
    DisplayAttribute display = field.GetCustomAttribute<DisplayAttribute>(inherit: false);
    if (display != null)
    {
        string name = display.GetName();
        if (!String.IsNullOrEmpty(name))
        {
            return name;
        }
    }

    return field.Name;
}

可以看到在方法GetDisplayName中检查enum成员是否存在DisplayAttribute。如果该显示属性存在,则将名称设置为DisplayAttribute.GetName()方法的结果。

将这些组合起来,我们可以修改enum以使用DisplayAttribute而不是DescriptionAttribute,并将Name属性设置为要显示的值。

public enum SearchBy
{
    [Display(Name = "SID/PID")]
    SID = 1,
    [Display(Name = "Name")]
    Name,
    [Display(Name = "Birth Date")]
    DOB,
    [Display(Name = "Cause#")]
    Cause
}

这将给你希望中的结果。

在此输入图像描述

希望对你有所帮助。


谢谢你,Nico。这很有帮助,但在视图页面中,我应该用什么替换EnumDropDownListFor? - Santosh_Sams
1
经过一点研究,我明白了,我必须编写显示模板以正确呈现枚举并将其视为下拉列表,对吗?如果我错了,请纠正我。我在这里找到了一篇相关文章:http://www.codeproject.com/Articles/776908/Dealing-with-Enum-in-MVC - Santosh_Sams

6

我创建了一个帮助类,尝试不同类型的属性。我需要它是因为我正在使用Bootstrap和https://github.com/civicsource/enums以及https://silviomoreto.github.io/bootstrap-select/

public static class EnumHelper<T>
    {
        static EnumHelper()
        {
            var enumType = typeof(T);
            if (!enumType.IsEnum) { throw new ArgumentException("Type '" + enumType.Name + "' is not an enum"); }
        }

        public static string GetEnumDescription(T value)
        {
            var fi = typeof(T).GetField(value.ToString());
            var attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : value.ToString();
        }

        public static IEnumerable<SelectListItem> GetSelectList()
        {
            var groupDictionary = new Dictionary<string, SelectListGroup>();

            var enumType = typeof(T);
            var fields = from field in enumType.GetFields()
                         where field.IsLiteral
                         select field;

            foreach (var field in fields)
            {
                var display = field.GetCustomAttribute<DisplayAttribute>(false);
                var description = field.GetCustomAttribute<DescriptionAttribute>(false);
                var group = field.GetCustomAttribute<CategoryAttribute>(false);

                var text = display?.GetName() ?? display?.GetShortName() ?? display?.GetDescription() ?? display?.GetPrompt() ?? description?.Description ?? field.Name;
                var value = field.Name;
                var groupName = display?.GetGroupName() ?? group?.Category ?? string.Empty;
                if (!groupDictionary.ContainsKey(groupName)) { groupDictionary.Add(groupName, new SelectListGroup { Name = groupName }); }

                yield return new SelectListItem
                {
                    Text = text,
                    Value = value,
                    Group = groupDictionary[groupName],
                };
            }
        }
    }

你可以这样调用:

<div class="form-group">
   @Html.LabelFor(model => model.Address.State, htmlAttributes: new { @class = "control-label col-md-2" })
   <div class="col-sm-4">
      @Html.DropDownListFor(model => model.Address.State, EnumHelper<StateProvince>.GetSelectList(), new { @class = "selectpicker show-menu-arrow", data_live_search = "true" })
      @Html.ValidationMessageFor(model => model.Address.State, "", new { @class = "text-danger" })
   </div>
</div>

Result


5
如果你使用的是 .Net Framework 4.0 或更高版本,则无需创建帮助类。你只需将 Display 属性与 EnumDropDownListFor 结合使用即可。
public enum SearchBy
{
    [Display(Name = "SID/PID")]
    SID = 1,
    [Display(Name = "Name")]
    Name,
    [Display(Name = "Birth Date")]
    DOB,
    [Display(Name = "Cause#")]
    Cause
}

在您的视图中:
@Html.EnumDropDownListFor(model => model.SearchBy, "Search By", new { @class = "form-control" })

微软文档:

https://learn.microsoft.com/zh-cn/dotnet/api/system.componentmodel.dataannotations.displayattribute?view=netframework-4.8


2

给定:

public enum MyEnum
{
    [Description("This is the description if my member A")]
    A,
    [Description("This is the description if my member B")]
    B
}

我个人使用这个扩展方法从我的枚举中获取描述:

 public static string GetDescription(this Enum 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();
            }
        }

使用方法:
MyEnum.A.GetDescription();

希望这可以帮到你。

谢谢你,安德鲁。尼科帮我解决了这个问题。 - Santosh_Sams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接