How to get the Display Name Attribute of an Enum member via MVC razor code?

后端 未结 20 2391
孤街浪徒
孤街浪徒 2020-11-22 09:30

I\'ve got a property in my model called \"Promotion\" that its type is a flag enum called \"UserPromotion\". Members of my enum have display attributes set as follows:

相关标签:
20条回答
  • 2020-11-22 09:41

    For ASP.Net Core 3.0, this worked for me (credit to previous answerers).

    My Enum class:

    using System;
    using System.Linq;
    using System.ComponentModel.DataAnnotations;
    using System.Reflection;
    
    public class Enums
    {
        public enum Duration
        { 
            [Display(Name = "1 Hour")]
            OneHour,
            [Display(Name = "1 Day")]
            OneDay
        }
    
        // Helper method to display the name of the enum values.
        public static string GetDisplayName(Enum value)
        {
            return value.GetType()?
           .GetMember(value.ToString())?.First()?
           .GetCustomAttribute<DisplayAttribute>()?
           .Name;
        }
    }
    

    My View Model Class:

    public class MyViewModel
    {
        public Duration Duration { get; set; }
    }
    

    An example of a razor view displaying a label and a drop-down list. Notice the drop-down list does not require a helper method:

    @model IEnumerable<MyViewModel> 
    
    @foreach (var item in Model)
    {
        <label asp-for="@item.Duration">@Enums.GetDisplayName(item.Duration)</label>
        <div class="form-group">
            <label asp-for="@item.Duration" class="control-label">Select Duration</label>
            <select asp-for="@item.Duration" class="form-control"
                asp-items="Html.GetEnumSelectList<Enums.Duration>()">
            </select>
        </div>
    }
    
    0 讨论(0)
  • 2020-11-22 09:42

    You need to use a bit of reflection in order to access that attribute:

    var type = typeof(UserPromotion);
    var member = type.GetMember(Model.JobSeeker.Promotion.ToString());
    var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false);
    var name = ((DisplayAttribute)attributes[0]).Name;
    

    I recommend wrapping this method in a extension method or perform this in a view model.

    0 讨论(0)
  • 2020-11-22 09:42

    I tried doing this as an edit but it was rejected; I can't see why.

    The above will throw an exception if you call it with an Enum that has a mix of custom attributes and plain items, e.g.

    public enum CommentType
    {
        All = 1,
        Rent = 2,
        Insurance = 3,
        [Display(Name="Service Charge")]
        ServiceCharge = 4
    }
    

    So I've modified the code ever so slightly to check for custom attributes before trying to access them, and use the name if none are found.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    
    public static class EnumHelper<T>
    {
        public static IList<T> GetValues(Enum value)
        {
            var enumValues = new List<T>();
    
            foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
            {
                enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
            }
            return enumValues;
        }
    
        public static T Parse(string value)
        {
            return (T)Enum.Parse(typeof(T), value, true);
        }
    
        public static IList<string> GetNames(Enum value)
        {
            return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
        }
    
        public static IList<string> GetDisplayValues(Enum value)
        {
            return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
        }
    
        private static string lookupResource(Type resourceManagerProvider, string resourceKey)
        {
            foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
            {
                if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
                {
                    System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                    return resourceManager.GetString(resourceKey);
                }
            }
    
            return resourceKey; // Fallback with the key name
        }
    
        public static string GetDisplayValue(T value)
        {
            var fieldInfo = value.GetType().GetField(value.ToString());
    
            var descriptionAttributes = fieldInfo.GetCustomAttributes(
                typeof(DisplayAttribute), false) as DisplayAttribute[];
    
            if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null)
                return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);
    
            if (descriptionAttributes == null) return string.Empty;
            return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
        }
    }
    
    0 讨论(0)
  • 2020-11-22 09:43

    UPDATE

    First solution was focused on getting display names from enum. Code below should be exact solution for your problem.

    You can use this helper class for enums:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    
    public static class EnumHelper<T>
        where T : struct, Enum // This constraint requires C# 7.3 or later.
    {
        public static IList<T> GetValues(Enum value)
        {
            var enumValues = new List<T>();
    
            foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
            {
                enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false));
            }
            return enumValues;
        }
    
        public static T Parse(string value)
        {
            return (T)Enum.Parse(typeof(T), value, true);
        }
    
        public static IList<string> GetNames(Enum value)
        {
            return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList();
        }
    
        public static IList<string> GetDisplayValues(Enum value)
        {
            return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList();
        }
    
        private static string lookupResource(Type resourceManagerProvider, string resourceKey)
        {
            foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
            {
                if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager))
                {
                    System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null);
                    return resourceManager.GetString(resourceKey);
                }
            }
    
            return resourceKey; // Fallback with the key name
        }
    
        public static string GetDisplayValue(T value)
        {
            var fieldInfo = value.GetType().GetField(value.ToString());
    
            var descriptionAttributes = fieldInfo.GetCustomAttributes(
                typeof(DisplayAttribute), false) as DisplayAttribute[];
    
            if (descriptionAttributes[0].ResourceType != null)
                return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name);
    
            if (descriptionAttributes == null) return string.Empty;
            return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString();
        }
    }
    

    And then you can use it in your view as following:

    <ul>
        @foreach (var value in @EnumHelper<UserPromotion>.GetValues(UserPromotion.None))
        {
             if (value == Model.JobSeeker.Promotion)
            {
                var description = EnumHelper<UserPromotion>.GetDisplayValue(value);
                <li>@Html.DisplayFor(e => description )</li>
            }
        }
    </ul>
    

    Hope it helps! :)

    0 讨论(0)
  • 2020-11-22 09:43

    Building on Todd's great answer which built on Aydin's great answer, here's a generic extension method that doesn't require any type parameters.

    /// <summary>
    /// Gets human-readable version of enum.
    /// </summary>
    /// <returns>DisplayAttribute.Name property of given enum.</returns>
    public static string GetDisplayName<T>(this T enumValue) where T : IComparable, IFormattable, IConvertible
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("Argument must be of type Enum");
    
        DisplayAttribute displayAttribute = enumValue.GetType()
                                                     .GetMember(enumValue.ToString())
                                                     .First()
                                                     .GetCustomAttribute<DisplayAttribute>();
    
        string displayName = displayAttribute?.GetName();
    
        return displayName ?? enumValue.ToString();
    }
    

    I needed this for my project because something like the below code, where not every member of the enum has a DisplayAttribute, does not work with Todd's solution:

    public class MyClass
    {
        public enum MyEnum 
        {
            [Display(Name="ONE")]
            One,
            // No DisplayAttribute
            Two
        }
        public void UseMyEnum()
        {
            MyEnum foo = MyEnum.One;
            MyEnum bar = MyEnum.Two;
            Console.WriteLine(foo.GetDisplayName());
            Console.WriteLine(bar.GetDisplayName());
        }
    }
    // Output:
    //
    // ONE
    // Two
    

    If this is a complicated solution to a simple problem, please let me know, but this was the fix I used.

    0 讨论(0)
  • 2020-11-22 09:44

    I have two solutions for this Question.

    1. The first solution is on getting display names from enum.
    public enum CourseLocationTypes
    {
        [Display(Name = "On Campus")]
        OnCampus,
        [Display(Name = "Online")]
        Online,
        [Display(Name = "Both")]
        Both
    }
    
    public static string DisplayName(this Enum value)
    {
        Type enumType = value.GetType();
        string enumValue = Enum.GetName(enumType, value);
        MemberInfo member = enumType.GetMember(enumValue)[0];
    
        object[] attrs = member.GetCustomAttributes(typeof(DisplayAttribute), false);
        string outString = ((DisplayAttribute)attrs[0]).Name;
    
        if (((DisplayAttribute)attrs[0]).ResourceType != null)
        {
            outString = ((DisplayAttribute)attrs[0]).GetName();
        }
    
        return outString;
    }
    
    <h3 class="product-title white">@Model.CourseLocationType.DisplayName()</h3>
    
    1. The second Solution is on getting display name from enum name but that will be enum split in developer language it's called patch.
    public static string SplitOnCapitals(this string text)
    {
            var r = new Regex(@"
                (?<=[A-Z])(?=[A-Z][a-z]) |
                 (?<=[^A-Z])(?=[A-Z]) |
                 (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
    
            return r.Replace(text, " ");
    }
    
     <div class="widget-box pt-0">
         @foreach (var item in Enum.GetNames(typeof(CourseLocationType)))
         {
             <label class="pr-2 pt-1">
                 @Html.RadioButtonFor(x => x.CourseLocationType, item, new { type = "radio", @class = "iCheckBox control-label" })&nbsp; @item.SplitOnCapitals()
             </label>
         }
         @Html.ValidationMessageFor(x => x.CourseLocationType)
     </div>
    
    0 讨论(0)
提交回复
热议问题