Enum с целыми строками
У меня есть общедоступный enum
, например:
public enum occupancyTimeline
{
TwelveMonths,
FourteenMonths,
SixteenMonths,
EighteenMonths
}
который я буду использовать для меню DropDown
, например:
@Html.DropDownListFor(model => model.occupancyTimeline,
new SelectList(Enum.GetValues(typeof(CentralParkLCPreview.Models.occupancyTimeline))), "")
Теперь я ищу, чтобы мои ценности были такими, как
12 месяцев, 14 месяцев, 16 месяцев, 18 месяцев вместо TweleveMonths, FourteenMonths, SixteenMonths, EighteenMonths
Как бы это сделать?
Ответы
Ответ 1
Вы можете проверить эту ссылку
его решение предназначалось для Asp.NET, но благодаря простой модификации вы можете использовать его в MVC, например
/// <span class="code-SummaryComment"><summary></span>
/// Provides a description for an enumerated type.
/// <span class="code-SummaryComment"></summary></span>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,
AllowMultiple = false)]
public sealed class EnumDescriptionAttribute : Attribute
{
private string description;
/// <span class="code-SummaryComment"><summary></span>
/// Gets the description stored in this attribute.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><value>The description stored in the attribute.</value></span>
public string Description
{
get
{
return this.description;
}
}
/// <span class="code-SummaryComment"><summary></span>
/// Initializes a new instance of the
/// <span class="code-SummaryComment"><see cref="EnumDescriptionAttribute"/> class.</span>
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="description">The description to store in this attribute.</span>
/// <span class="code-SummaryComment"></param></span>
public EnumDescriptionAttribute(string description)
: base()
{
this.description = description;
}
}
помощник, который позволит вам создать список ключей и значений
/// <span class="code-SummaryComment"><summary></span>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// <span class="code-SummaryComment"></summary></span>
public static class EnumHelper
{
/// <span class="code-SummaryComment"><summary></span>
/// Gets the <span class="code-SummaryComment"><see cref="DescriptionAttribute" /> of an <see cref="Enum" /></span>
/// type value.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="value">The <see cref="Enum" /> type value.</param></span>
/// <span class="code-SummaryComment"><returns>A string containing the text of the</span>
/// <span class="code-SummaryComment"><see cref="DescriptionAttribute"/>.</returns></span>
public static string GetDescription(Enum value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}
/// <span class="code-SummaryComment"><summary></span>
/// Converts the <span class="code-SummaryComment"><see cref="Enum" /> type to an <see cref="IList" /> </span>
/// compatible object.
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="type">The <see cref="Enum"/> type.</param></span>
/// <span class="code-SummaryComment"><returns>An <see cref="IList"/> containing the enumerated</span>
/// type value and description.<span class="code-SummaryComment"></returns></span>
public static IList ToList(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);
foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}
return list;
}
}
тогда вы украшаете свое перечисление как
public enum occupancyTimeline
{
[EnumDescriptionAttribute ("12 months")]
TwelveMonths,
[EnumDescriptionAttribute ("14 months")]
FourteenMonths,
[EnumDescriptionAttribute ("16 months")]
SixteenMonths,
[EnumDescriptionAttribute ("18 months")]
EighteenMonths
}
вы можете использовать его в контроллере, чтобы заполнить выпадающий список как
ViewBag.occupancyTimeline =new SelectList( EnumHelper.ToList(typeof(occupancyTimeline)),"Value","Key");
и, на ваш взгляд, вы можете использовать следующие
@Html.DropdownList("occupancyTimeline")
надеюсь, что это поможет вам
Ответ 2
Я сделал себе метод расширения, который я теперь использую в каждом проекте:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Mvc;
namespace App.Extensions
{
public static class EnumExtensions
{
public static SelectList ToSelectList(Type enumType)
{
return new SelectList(ToSelectListItems(enumType));
}
public static List<SelectListItem> ToSelectListItems(Type enumType, Func<object, bool> itemSelectedAction = null)
{
var arr = Enum.GetValues(enumType);
return (from object item in arr
select new SelectListItem
{
Text = ((Enum)item).GetDescriptionEx(typeof(MyResources)),
Value = ((int)item).ToString(),
Selected = itemSelectedAction != null && itemSelectedAction(item)
}).ToList();
}
public static string GetDescriptionEx(this Enum @this)
{
return GetDescriptionEx(@this, null);
}
public static string GetDescriptionEx(this Enum @this, Type resObjectType)
{
// If no DescriptionAttribute is present, set string with following name
// "Enum_<EnumType>_<EnumValue>" to be the default value.
// Could also make some code to load value from resource.
var defaultResult = $"Enum_{@this.GetType().Name}_{@this}";
var fi = @this.GetType().GetField(@this.ToString());
if (fi == null)
return defaultResult;
var customAttributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (customAttributes.Length <= 0 || customAttributes.IsNot<DescriptionAttribute[]>())
{
if (resObjectType == null)
return defaultResult;
var res = GetFromResource(defaultResult, resObjectType);
return res ?? defaultResult;
}
var attributes = (DescriptionAttribute[])customAttributes;
var result = attributes.Length > 0 ? attributes[0].Description : defaultResult;
return result ?? defaultResult;
}
public static string GetFromResource(string defaultResult, Type resObjectType)
{
var searchingPropName = defaultResult;
var props = resObjectType.GetProperties();
var prop = props.FirstOrDefault(t => t.Name.Equals(searchingPropName, StringComparison.InvariantCultureIgnoreCase));
if (prop == null)
return defaultResult;
var res = prop.GetValue(resObjectType) as string;
return res;
}
public static bool IsNot<T>(this object @this)
{
return !(@this is T);
}
}
}
И затем используйте его как это (например, в View.cshtml) (код для разбиения на две строки для ясности, также может сделать oneliner):
// A SelectList without default value selected
var list1 = EnumExtensions.ToSelectListItems(typeof(occupancyTimeline));
@Html.DropDownListFor(model => model.occupancyTimeline, new SelectList(list1), "")
// A SelectList with default value selected if equals "DesiredValue"
// Selection is determined by lambda expression as a second parameter to
// ToSelectListItems method which returns bool.
var list2 = EnumExtensions.ToSelectListItems(typeof(occupancyTimeline), item => (occupancyTimeline)item == occupancyTimeline.DesiredValue));
@Html.DropDownListFor(model => model.occupancyTimeline, new SelectList(list2), "")
Обновление
Основываясь на предположении Фила, я обновил выше код с возможностью считывать значение отображения enum с некоторого ресурса (если есть). Имя элемента в ресурсе должно быть в форме Enum_<EnumType>_<EnumValue>
(например, Enum_occupancyTimeline_TwelveMonths
). Таким образом вы можете предоставить текст для значений enum в файле ресурсов, не украсив ваши значения перечисления некоторыми атрибутами. Тип ресурса (MyResource) включен непосредственно в метод ToSelectItems. Вы можете извлечь его как параметр метода расширения.
Другим способом присвоения имен значениям перечисления является атрибут Description (это работает без адаптации кода к изменениям, которые я сделал). Например:
public enum occupancyTimeline
{
[Description("12 Months")]
TwelveMonths,
[Description("14 Months")]
FourteenMonths,
[Description("16 Months")]
SixteenMonths,
[Description("18 Months")]
EighteenMonths
}
Ответ 3
Сделать расширение Описание для перечисления
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.ComponentModel;
public static class EnumerationExtensions
{
//This procedure gets the <Description> attribute of an enum constant, if any.
//Otherwise, it gets the string name of then enum member.
[Extension()]
public static string Description(Enum EnumConstant)
{
Reflection.FieldInfo fi = EnumConstant.GetType().GetField(EnumConstant.ToString());
DescriptionAttribute[] attr = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attr.Length > 0) {
return attr(0).Description;
} else {
return EnumConstant.ToString();
}
}
}
Ответ 4
Вы можете использовать EnumDropDownListFor
для этой цели. Вот пример того, что вы хотите. (Просто не забудьте использовать EnumDropDownListFor
, вы должны использовать ASP MVC 5 и Visual Studio 2015.):
Ваш вид:
@using System.Web.Mvc.Html
@using WebApplication2.Models
@model WebApplication2.Models.MyClass
@{
ViewBag.Title = "Index";
}
@Html.EnumDropDownListFor(model => model.occupancyTimeline)
И ваша модель:
public enum occupancyTimeline
{
[Display(Name = "12 months")]
TwelveMonths,
[Display(Name = "14 months")]
FourteenMonths,
[Display(Name = "16 months")]
SixteenMonths,
[Display(Name = "18 months")]
EighteenMonths
}
Ссылка: Что нового в ASP.NET MVC 5.1
Ответ 5
public namespace WebApplication16.Controllers{
public enum occupancyTimeline:int {
TwelveMonths=12,
FourteenMonths=14,
SixteenMonths=16,
EighteenMonths=18
}
public static class MyExtensions {
public static SelectList ToSelectList(this string enumObj)
{
var values = from occupancyTimeline e in Enum.GetValues(typeof(occupancyTimeline))
select new { Id = e, Name = string.Format("{0} Months",Convert.ToInt32(e)) };
return new SelectList(values, "Id", "Name", enumObj);
}
}
}
Использование
@using WebApplication16.Controllers
@Html.DropDownListFor(model => model.occupancyTimeline,Model.occupancyTimeline.ToSelectList());
Ответ 6
public enum occupancyTimeline
{
TwelveMonths=0,
FourteenMonths=1,
SixteenMonths=2,
EighteenMonths=3
}
public string[] enumString = {
"12 Months", "14 Months", "16 Months", "18 Months"};
string selectedEnum = enumString[(int)occupancyTimeLine.TwelveMonths];
или
public enum occupancyTimeline
{
TwelveMonths,
FourteenMonths,
SixteenMonths,
EighteenMonths
}
public string[] enumString = {
"12 Months", "14 Months", "16 Months", "18 Months"};
string selectedEnum = enumString[DropDownList.SelectedIndex];
Ответ 7
В дополнение к использованию атрибута для описания (см. другие ответы или использование Google), я часто использую файлы RESX, где ключ представляет собой текст перечисления (например, TwelveMonths
), а значение - желаемый текст.
Тогда относительно тривиально выполнять функцию, которая возвращает желаемый текст, а также легко переводить значения для многоязычных приложений.
Я также хотел бы добавить некоторые модульные тесты, чтобы гарантировать, что все значения имеют связанный текст. Если есть некоторые исключения (например, возможно, значение Count
в конце, то unit test исключает те из проверки.
Все это не очень сложно и довольно гибко. Если вы используете DescriptionAttribute
и хотите многоязычную поддержку, вам все равно нужно использовать файлы ресурсов.
Обычно у меня есть один класс для получения значений (отображаемое имя) для типа enum
, которые необходимо отобразить, и одного файла unit test для каждого файла ресурсов, хотя у меня есть некоторые другие классы для некоторого общего кода, например, для сравнения ключа в файл ресурса со значением в enum
для unit test (и одна перегрузка позволяет указать исключение).
Кстати, в таком случае имеет смысл иметь значение enum
, соответствующее числу месяцев (например, TwelveMonths = 12
). В этом случае вы также можете использовать string.Format
для отображаемых значений, а также иметь исключения в ресурсе (например, сингулярные).
Ответ 8
MVC 5.1
@Html.EnumDropDownListFor(model => model.MyEnum)
MVC 5
@Html.DropDownList("MyType",
EnumHelper.GetSelectList(typeof(MyType)) ,
"Select My Type",
new { @class = "form-control" })
MVC 4
Вы можете сослаться на эту ссылку Создать выпадающий список из Enum в Asp.Net MVC
Ответ 9
Шаблон публикации для вашего решения, вы можете изменить некоторые части в соответствии с вашими потребностями.
Определить общий EnumHelper для формирования перечислений:
public abstract class EnumHelper<T> where T : struct
{
static T[] _valuesCache = (T[])Enum.GetValues(typeof(T));
public virtual string GetEnumName()
{
return GetType().Name;
}
public static T[] GetValuesS()
{
return _valuesCache;
}
public T[] GetValues()
{
return _valuesCache;
}
virtual public string EnumToString(T value)
{
return value.ToString();
}
}
Определите вспомогательный помощник расширения раскрывающегося списка MVC:
public static class SystemExt
{
public static MvcHtmlString DropDownListT<T>(this HtmlHelper htmlHelper,
string name,
EnumHelper<T> enumHelper,
string value = null,
string nonSelected = null,
IDictionary<string, object> htmlAttributes = null)
where T : struct
{
List<SelectListItem> items = new List<SelectListItem>();
if (nonSelected != null)
{
items.Add(new SelectListItem()
{
Text = nonSelected,
Selected = string.IsNullOrEmpty(value),
});
}
foreach (T item in enumHelper.GetValues())
{
if (enumHelper.EnumToIndex(item) >= 0)
items.Add(new SelectListItem()
{
Text = enumHelper.EnumToString(item),
Value = item.ToString(), //enumHelper.Unbox(item).ToString()
Selected = value == item.ToString(),
});
}
return htmlHelper.DropDownList(name, items, htmlAttributes);
}
}
Каждый раз, когда вам нужно форматировать некоторые Enums, определите EnumHelper для конкретного перечисления T:
public class OccupancyTimelineHelper : EnumHelper<OccupancyTimeline>
{
public override string EnumToString(occupancyTimeline value)
{
switch (value)
{
case OccupancyTimelineHelper.TwelveMonths:
return "12 Month";
case OccupancyTimelineHelper.FourteenMonths:
return "14 Month";
case OccupancyTimelineHelper.SixteenMonths:
return "16 Month";
case OccupancyTimelineHelper.EighteenMonths:
return "18 Month";
default:
return base.EnumToString(value);
}
}
}
Наконец, используйте код в представлении:
@Html.DropDownListT("occupancyTimeline", new OccupancyTimelineHelper())
Ответ 10
Я бы выбрал несколько иной и, возможно, более простой подход:
public static List<int> PermittedMonths = new List<int>{12, 14, 16, 18};
Тогда просто:
foreach(var permittedMonth in PermittedMonths)
{
MyDropDownList.Items.Add(permittedMonth.ToString(), permittedMonth + " months");
}
Использование перечислений в том, как вы описываете я чувствую, может быть немного ловушкой.