Как получить атрибут отображаемого имени члена Enum с помощью бритвенного кода MVC?
В моей модели есть свойство "Поощрение", типом которого является перечисление флага "UserPromotion". Члены моего enum имеют атрибуты отображения, установленные следующим образом:
[Flags]
public enum UserPromotion
{
None = 0x0,
[Display(Name = "Send Job Offers By Mail")]
SendJobOffersByMail = 0x1,
[Display(Name = "Send Job Offers By Sms")]
SendJobOffersBySms = 0x2,
[Display(Name = "Send Other Stuff By Sms")]
SendPromotionalBySms = 0x4,
[Display(Name = "Send Other Stuff By Mail")]
SendPromotionalByMail = 0x8
}
Теперь я хочу иметь возможность создать, скажем, ul на мой взгляд, чтобы показать выбранные значения моего свойства "Продвижение". Это то, что я сделал до сих пор, но проблема в том, как я могу получить отображаемые имена здесь?
<ul>
@foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
{
var currentPromotion = (int)Model.JobSeeker.Promotion;
if ((currentPromotion & aPromotion) == aPromotion)
{
<li>Here I don't know how to get the display attribute of "currentPromotion".</li>
}
}
</ul>
26 ответов
ОБНОВИТЬ
Первое решение было сосредоточено на получении отображаемых имен из enum. Код ниже должен быть точным решением вашей проблемы.
Вы можете использовать этот вспомогательный класс для перечислений:
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[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();
}
}
И тогда вы можете использовать его на ваш взгляд следующим образом:
<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>
Надеюсь, поможет!:)
Один вкладыш - Свободный синтаксис
public static class Extensions
{
/// <summary>
/// A generic extension method that aids in reflecting
/// and retrieving any attribute that is applied to an `Enum`.
/// </summary>
public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
where TAttribute : Attribute
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<TAttribute>();
}
}
пример
public enum Season
{
[Display(Name = "It's autumn")]
Autumn,
[Display(Name = "It's winter")]
Winter,
[Display(Name = "It's spring")]
Spring,
[Display(Name = "It's summer")]
Summer
}
public class Foo
{
public Season Season = Season.Summer;
public void DisplayName()
{
var seasonDisplayName = Season.GetAttribute<DisplayAttribute>();
Console.WriteLine("Which season is it?");
Console.WriteLine (seasonDisplayName.Name);
}
}
Выход
Какой сезон это?
Это лето
Основываясь на отличном ответе Айдына, вот метод расширения, который не требует никаких параметров типа.
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetName();
}
}
ПРИМЕЧАНИЕ. GetName() следует использовать вместо свойства Name. Это гарантирует, что локализованная строка будет возвращена, если используется свойство атрибута ResourceType.
пример
Чтобы использовать его, просто укажите значение enum в вашем представлении.
@{
UserPromotion promo = UserPromotion.SendJobOffersByMail;
}
Promotion: @promo.GetDisplayName()
Выход
Промоушен: отправка вакансий по почте
Исходя из ответа Айдына, я бы предложил менее "дублирующую" реализацию (потому что мы могли бы легко получить Type
от Enum
само значение вместо предоставления его в качестве параметра:
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType().GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.Name;
}
РЕДАКТИРОВАТЬ (на основе комментария @Vahagn Nahapetyan)
public static string GetDisplayName(this Enum enumValue)
{
return enumValue.GetType()?
.GetMember(enumValue.ToString())?
.First()?
.GetCustomAttribute<DisplayAttribute>()?
.Name;
}
Теперь мы можем использовать его очень чисто:
public enum Season
{
[Display(Name = "The Autumn")]
Autumn,
[Display(Name = "The Weather")]
Winter,
[Display(Name = "The Tease")]
Spring,
[Display(Name = "The Dream")]
Summer
}
Season.Summer.GetDisplayName();
Что приводит к
"Мечта"
Если вы используете MVC 5.1 или выше, есть более простой и понятный способ: просто используйте аннотацию данных (из System.ComponentModel.DataAnnotations
пространство имен), как показано ниже:
public enum Color
{
[Display(Name = "Dark red")]
DarkRed,
[Display(Name = "Very dark red")]
VeryDarkRed,
[Display(Name = "Red or just black?")]
ReallyDarkRed
}
И, видимо, просто поместите его в правильный помощник HTML:
@Html.EnumDropDownListFor(model => model.Color)
Основываясь на великолепном ответе Тодда, основанном на отличном ответе Айдына, вот общий метод расширения, который не требует каких-либо параметров типа.
/// <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();
}
Мне это нужно для моего проекта, потому что что-то вроде приведенного ниже кода, где не каждый член enum имеет DisplayAttribute
, не работает с решением Тодда:
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
Если это сложное решение простой проблемы, пожалуйста, дайте мне знать, но это было исправление, которое я использовал.
В .NET5 я использовал DisplayTextFor без использования вспомогательных методов или методов расширения:
@Html.DisplayTextFor(m => m.SomeEnumProperty)
Где
SomeEnumProperty
имеет значение:
public enum MyEnum
{
[Display(Name = "Not started")]
NotStarted = 0,
[Display(Name = "Weird display name instead of just 'Started'")]
Started = 1,
}
Вы можете использовать метод Type.GetMember, а затем получить информацию об атрибуте, используя отражение:
// display attribute of "currentPromotion"
var type = typeof(UserPromotion);
var memberInfo = type.GetMember(currentPromotion.ToString());
var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false);
var description = ((DisplayAttribute)attributes[0]).Name;
Здесь было несколько похожих постов:
Получение атрибутов значения Enum
Как заставить MVC3 DisplayFor отображать значение атрибута отображения Enum?
Для ASP.Net Core 3.0 это сработало для меня (благодарность предыдущим ответчикам).
Мой класс Enum:
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;
}
}
Мой класс модели представления:
public class MyViewModel
{
public Duration Duration { get; set; }
}
Пример вида бритвы с меткой и раскрывающимся списком. Обратите внимание, что раскрывающийся список не требует вспомогательного метода:
@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>
}
С Core 2.1,
public static string GetDisplayName(Enum enumValue)
{
return enumValue.GetType()?
.GetMember(enumValue.ToString())?[0]?
.GetCustomAttribute<DisplayAttribute>()?
.Name;
}
Объединяя все крайние случаи вместе сверху:
- члены перечисления с именами членов базового объекта (
Equals
,ToString
) - по желанию
Display
атрибут
вот мой код:
public enum Enum
{
[Display(Name = "What a weird name!")]
ToString,
Equals
}
public static class EnumHelpers
{
public static string GetDisplayName(this Enum enumValue)
{
var enumType = enumValue.GetType();
return enumType
.GetMember(enumValue.ToString())
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == enumType)
.First()
.GetCustomAttribute<DisplayAttribute>()?.Name ?? enumValue.ToString();
}
}
void Main()
{
Assert.Equals("What a weird name!", Enum.ToString.GetDisplayName());
Assert.Equals("Equals", Enum.Equals.GetDisplayName());
}
<ul>
@foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
{
var currentPromotion = (int)Model.JobSeeker.Promotion;
if ((currentPromotion & aPromotion) == aPromotion)
{
<li>@Html.DisplayFor(e => currentPromotion)</li>
}
}
</ul>
У меня есть два решения по этому вопросу.
- Первое решение - получить отображаемые имена из 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>
- Второе решение заключается в получении отображаемого имени из имени перечисления, но это будет разделение перечисления на языке разработчика, которое называется патчем.
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" }) @item.SplitOnCapitals()
</label>
}
@Html.ValidationMessageFor(x => x.CourseLocationType)
</div>
Мне жаль это делать, но я не мог использовать другие ответы как есть и не успел выяснить это в комментариях.
Использует синтаксис C# 6.
static class EnumExtensions
{
/// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member
/// returns null if there isnt an attribute
public static string DisplayNameOrEnumName(this Enum value)
// => value.DisplayNameOrDefault() ?? value.ToString()
{
// More efficient form of ^ based on http://stackru.com/a/17034624/11635
var enumType = value.GetType();
var enumMemberName = Enum.GetName(enumType, value);
return enumType
.GetEnumMemberAttribute<DisplayAttribute>(enumMemberName)
?.GetName() // Potentially localized
?? enumMemberName; // Or fall back to the enum name
}
/// returns the localized Name, if a [Display] attribute is applied to the enum member
/// returns null if there is no attribute
public static string DisplayNameOrDefault(this Enum value) =>
value.GetEnumMemberAttribute<DisplayAttribute>()?.GetName();
static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute =>
value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString());
static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute =>
enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>();
}
Вам нужно использовать немного отражения для доступа к этому атрибуту:
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;
Я рекомендую обернуть этот метод в метод расширения или выполнить его в модели представления.
Для отображения только ENUM в имени атрибута дисплея просто использовать Microsoft.AspNetCore.Mvc.Rendering «S
@Html.DisplayFor(x => EnumType.EnumValue)
Этого было бы достаточно.
Для отображения SelectList напишите следующее:
<select id="someIdForTheEndPoint" asp-items="Html.GetEnumSelectList<EnumType>()">
<option selected="selected" value="">Select value</option>
</select>
Основываясь далее на ответах Айдына и Тодда, вот метод расширения, который также позволяет вам получить имя из файла ресурсов.
using AppResources;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Resources;
public static class EnumExtensions
{
public static string GetDisplayName(this Enum enumValue)
{
var enumMember= enumValue.GetType()
.GetMember(enumValue.ToString());
DisplayAttribute displayAttrib = null;
if (enumMember.Any()) {
displayAttrib = enumMember
.First()
.GetCustomAttribute<DisplayAttribute>();
}
string name = null;
Type resource = null;
if (displayAttrib != null)
{
name = displayAttrib.Name;
resource = displayAttrib.ResourceType;
}
return String.IsNullOrEmpty(name) ? enumValue.ToString()
: resource == null ? name
: new ResourceManager(resource).GetString(name);
}
}
и использовать его как
public enum Season
{
[Display(ResourceType = typeof(Resource), Name = Season_Summer")]
Summer
}
Обновление 2020: обновленная версия функции, предоставляемая многими участниками этого потока, но теперь для C# 7.3 и новее:
Теперь вы можете ограничить общие методы типами перечислений, чтобы вы могли написать одно расширение метода, чтобы использовать его со всеми своими перечислениями следующим образом:
Общий метод расширения:
public static string ATexto<T>(this T enumeración) where T : struct, Enum {
var tipo = enumeración.GetType();
return tipo.GetMember(enumeración.ToString())
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo).First()
.GetCustomAttribute<DisplayAttribute>()?.Name ?? enumeración.ToString();
}
Перечисление:
public enum TipoImpuesto {
IVA, INC, [Display(Name = "IVA e INC")]IVAeINC, [Display(Name = "No aplica")]NoAplica };
Как это использовать:
var tipoImpuesto = TipoImpuesto.IVAeINC;
var textoTipoImpuesto = tipoImpuesto.ATexto(); // Prints "IVA e INC".
Бонус, перечисления с флагами: если вы имеете дело с обычными перечислениями, описанной выше функции достаточно, но если какое-либо из ваших перечислений может принимать несколько значений с использованием флагов, вам нужно будет изменить его следующим образом (в этом коде используется C#8 функции):
public static string ATexto<T>(this T enumeración) where T : struct, Enum {
var tipo = enumeración.GetType();
var textoDirecto = enumeración.ToString();
string obtenerTexto(string textoDirecto) => tipo.GetMember(textoDirecto)
.Where(x => x.MemberType == MemberTypes.Field && ((FieldInfo)x).FieldType == tipo)
.First().GetCustomAttribute<DisplayAttribute>()?.Name ?? textoDirecto;
if (textoDirecto.Contains(", ")) {
var texto = new StringBuilder();
foreach (var textoDirectoAux in textoDirecto.Split(", ")) {
texto.Append($"{obtenerTexto(textoDirectoAux)}, ");
}
return texto.ToString()[0..^2];
} else {
return obtenerTexto(textoDirecto);
}
}
Перечисление с флагами:
[Flags] public enum TipoContribuyente {
[Display(Name = "Común")] Común = 1,
[Display(Name = "Gran Contribuyente")] GranContribuyente = 2,
Autorretenedor = 4,
[Display(Name = "Retenedor de IVA")] RetenedorIVA = 8,
[Display(Name = "Régimen Simple")] RégimenSimple = 16 }
Как это использовать:
var tipoContribuyente = TipoContribuyente.RetenedorIVA | TipoContribuyente.GranContribuyente;
var textoAux = tipoContribuyente.ATexto(); // Prints "Gran Contribuyente, Retenedor de IVA".
Возможно, это обман, но это работает:
@foreach (var yourEnum in Html.GetEnumSelectList<YourEnum>())
{
@yourEnum.Text
}
Это работало в Asp.Net MVC 5.
В вашем классе модели User.cs.
public enum Expertise
{
[Display(Name = "JUNIOR")]
JUNIOR = 0,
[Display(Name = "SENIOR")]
SENIOR = 1
}
public class User
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
// the type must be the Enum class name
public Expertise ExpertiseLevel { get; set; }
}
В вашем представлении Index.cshtml
<div>
<h4>User</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Name)
</dd>
// This is the Property Name
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ExpertiseLevel)
</dt>
// This is the Value
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ExpertiseLevel)
</dd>
</dl>
</div>
Кстати,
ExpertiseLevel по-прежнему являетсяint
Чтобы получить его в вашей форме, например. в Create.cshtml вам необходимо получить значение как0
или1
, как показано ниже:
<div class="form-group">
<label asp-for="ExpertiseLevel" class="control-label"></label>
<span class="float-right" data-toggle="buttons">
<label asp-for="ExpertiseLevel" class="btn btn-outline-secondary" for="juniorCheckbox">
<input asp-for="ExpertiseLevel" type="radio" class="d-none" id="juniorCheckbox" value="0" checked>
Junior</label>
<label asp-for="ExpertiseLevel" class="btn btn-outline-secondary" for="expertCheckbox">
<input asp-for="ExpertiseLevel" type="radio" class="d-none" id="expertCheckbox" value="1">
Expert</label>
</span>
<span asp-validation-for="ExpertiseLevel" class="text-danger"></span>
</div>
Я хочу внести свой вклад с зависимым от культуры расширением перечисления GetDisplayName. Надеюсь, что это будет полезно для тех, кто ищет этот ответ, как я ранее:
"Стандартный" путь, как отметили Айдын Адн и Тодд:
public static string GetDisplayName(this Enum enumValue)
{
return enumValue
.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>()
.GetName();
}
"Культурно-зависимый" способ:
public static string GetDisplayName(this Enum enumValue, CultureInfo ci)
{
var displayAttr = enumValue
.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DisplayAttribute>();
var resMan = displayAttr.ResourceType?.GetProperty(@"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager;
return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName();
}
Приведенный ниже код поддерживает некоторые интересные функции!
Поддержка нулевых перечислений
Файлы ресурсов поддержки (если вы их использовали)
используя System.Linq; использование System.Reflection;
пространство имен Dtat;
публичный статический класс EnumHelper: объект {static EnumHelper(){}
public static string? GetDisplayName(this System.Enum? enumValue) { if (enumValue is null) { return null; } var currentType = enumValue.GetType(); if (currentType is null) { return enumValue.ToString(); } var membersInfo = currentType.GetMember(name: enumValue.ToString()) .FirstOrDefault(); if (membersInfo is null) { return enumValue.ToString(); } var displayAttribute = // using System.Reflection; membersInfo.GetCustomAttribute <System.ComponentModel.DataAnnotations.DisplayAttribute>(); if (displayAttribute is null) { return enumValue.ToString(); } var name = displayAttribute.Name; if (name is null) { return enumValue.ToString(); } if (displayAttribute.ResourceType is null) { return name; } var resourceType = displayAttribute.ResourceType; var resourceManager = new System.Resources .ResourceManager(resourceSource: resourceType); var value = resourceManager.GetString(name: name); if (value is null) { return name; } return value; }
}
Используя MVC5 вы можете использовать:
public enum UserPromotion
{
None = 0x0,
[Display(Name = "Send Job Offers By Mail")]
SendJobOffersByMail = 0x1,
[Display(Name = "Send Job Offers By Sms")]
SendJobOffersBySms = 0x2,
[Display(Name = "Send Other Stuff By Sms")]
SendPromotionalBySms = 0x4,
[Display(Name = "Send Other Stuff By Mail")]
SendPromotionalByMail = 0x8
}
тогда, если вы хотите создать выпадающий селектор, вы можете использовать:
@Html.EnumDropdownListFor(expression: model => model.PromotionSelector, optionLabel: "Select")
На основе предыдущих ответов я создал этот удобный помощник для поддержки всех свойств DisplayAttribute в удобочитаемой форме:
public static class EnumExtensions
{
public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue)
{
var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();
return new DisplayAttributeValues(enumValue, displayAttribute);
}
public sealed class DisplayAttributeValues
{
private readonly Enum enumValue;
private readonly DisplayAttribute displayAttribute;
public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute)
{
this.enumValue = enumValue;
this.displayAttribute = displayAttribute;
}
public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField();
public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter();
public int? Order => this.displayAttribute?.GetOrder();
public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty;
public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty;
public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString();
public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty;
public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString();
}
}
предположим, что ваше имя перечисления — OrderState. Используйте этот код:
@Html.DropDownList("selectList", new SelectList(Html.GetEnumSelectList<OrderState>(), "Value", "Text",ViewBag.selectedOrderState), new {@id="OrderState", @class = "form-control" })
и установите выбранный параметр в бэкэнде:
var selectedOrderState = ..Data.OrderState.GetHashCode();
ViewBag.selectedOrderState = selectedOrderState;
Я пытался сделать это как редактирование, но оно было отклонено; Я не понимаю почему.
Выше приведено исключение, если вы вызываете его с помощью Enum, который имеет сочетание пользовательских атрибутов и простых элементов, например
public enum CommentType
{
All = 1,
Rent = 2,
Insurance = 3,
[Display(Name="Service Charge")]
ServiceCharge = 4
}
Поэтому я немного изменил код, чтобы проверять наличие пользовательских атрибутов, прежде чем пытаться получить к ним доступ, и использовать имя, если ни одного не найдено.
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();
}
}