Reputation: 11861
I have a public enum
like so:
public enum occupancyTimeline
{
TwelveMonths,
FourteenMonths,
SixteenMonths,
EighteenMonths
}
which I will be using for a DropDown
menu like so:
@Html.DropDownListFor(model => model.occupancyTimeline,
new SelectList(Enum.GetValues(typeof(CentralParkLCPreview.Models.occupancyTimeline))), "")
Now I am looking for away to have my values like so
12 Months, 14 Months, 16 Months, 18 Months instead of TweleveMonths, FourteenMonths, SixteenMonths, EighteenMonths
How would I accomplish this?
Upvotes: 10
Views: 1755
Reputation: 133
You could use a getter casted into an integer, instead of trying to draw a property in a view from an Enum
. My problem was that I was writing the value of enum as string, but I would like to have its int value.
For example you could have the below two properties in a View Model class:
public enum SomeEnum
{
Test = 0,
Test1 = 1,
Test2,
}
public SomeEnum SomeEnum {get; init;}
public int SomeEnumId => (int) SomeEnum;
Then you could access your enum
through a razor View
as such:
<input type="hidden" asp-for="@Model.SomeEntityId" />
Upvotes: 0
Reputation: 10981
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);
}
}
}
Usage
@using WebApplication16.Controllers
@Html.DropDownListFor(model => model.occupancyTimeline,Model.occupancyTimeline.ToSelectList());
Upvotes: 1
Reputation: 6784
You might check this link
his solution was targeting the Asp.NET , but by easy modification you can use it in MVC like
/// <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;
}
}
the helper that will allow you to build a list of Key and Value
/// <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;
}
}
then you decorate your enum as
public enum occupancyTimeline
{
[EnumDescriptionAttribute ("12 months")]
TwelveMonths,
[EnumDescriptionAttribute ("14 months")]
FourteenMonths,
[EnumDescriptionAttribute ("16 months")]
SixteenMonths,
[EnumDescriptionAttribute ("18 months")]
EighteenMonths
}
you can use it in the controller to fill the drop down list as
ViewBag.occupancyTimeline =new SelectList( EnumHelper.ToList(typeof(occupancyTimeline)),"Value","Key");
and in your view, you can use the following
@Html.DropdownList("occupancyTimeline")
hope it will help you
Upvotes: 4
Reputation: 61737
I'd go for a slightly different and perhaps simpler approach:
public static List<int> PermittedMonths = new List<int>{12, 14, 16, 18};
Then simply:
foreach(var permittedMonth in PermittedMonths)
{
MyDropDownList.Items.Add(permittedMonth.ToString(), permittedMonth + " months");
}
Using enums in the way you describe I feel can be a bit of a trap.
Upvotes: 0
Reputation: 39956
You can use EnumDropDownListFor
for this purpose. Here is an example of what you want. (Just don't forget to use EnumDropDownListFor
you should use ASP MVC 5 and Visual Studio 2015.):
Your View:
@using System.Web.Mvc.Html
@using WebApplication2.Models
@model WebApplication2.Models.MyClass
@{
ViewBag.Title = "Index";
}
@Html.EnumDropDownListFor(model => model.occupancyTimeline)
And your model:
public enum occupancyTimeline
{
[Display(Name = "12 months")]
TwelveMonths,
[Display(Name = "14 months")]
FourteenMonths,
[Display(Name = "16 months")]
SixteenMonths,
[Display(Name = "18 months")]
EighteenMonths
}
Reference: What's New in ASP.NET MVC 5.1
Upvotes: 1
Reputation: 25108
Posting template for your solution, you may change some parts according your needs.
Define generic EnumHelper for formating enums:
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();
}
}
Define MVC generic drop down list extension helper:
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);
}
}
Any time you need to format some Enums define EnumHelper for particular enum 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);
}
}
}
Finally use the code in View:
@Html.DropDownListT("occupancyTimeline", new OccupancyTimelineHelper())
Upvotes: 0
Reputation: 3441
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
You can refer this link Create a dropdown list from an Enum in Asp.Net MVC
Upvotes: 0
Reputation: 1176
I've made myself an extension method, which I now use in every project:
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);
}
}
}
And then use it like this (in a View.cshtml, for example) (code is broken in two lines for clarity; could also make 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), "")
Update
Based on Phil's suggestion, I've updated above code with possibility to read enum's display value from some resource (if you have any). Name of item in a resource should be in a form of Enum_<EnumType>_<EnumValue>
(e.g. Enum_occupancyTimeline_TwelveMonths
). This way you can provide text for your enum values in resource file without decorating your enum values with some attributes. Type of resource (MyResource) is included directly inside ToSelectItems method. You could extract it as a parameter of an extension method.
The other way of naming enum values is applying Description attribute (this works without adapting the code to the changes I've made). For example:
public enum occupancyTimeline
{
[Description("12 Months")]
TwelveMonths,
[Description("14 Months")]
FourteenMonths,
[Description("16 Months")]
SixteenMonths,
[Description("18 Months")]
EighteenMonths
}
Upvotes: 4
Reputation: 3313
Make extension Description for enumeration
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();
}
}
}
Upvotes: 1
Reputation: 2623
In addition to using an attribute for description (see other answers or use Google), I often use RESX files where the key is the enum text (for ex. TwelveMonths
) and the value is the desired text.
Then it is relatively trivial to do a function that would return the desired text and it is also easy to translate values for multilingual applications.
I also like to add some unit tests to ensure that all values have an associated text. If there are some exceptions (like maybe a Count
value at the end, then the unit test would exclude those from the check.
All that stuff is not really hard and quite flexible. If you use DescriptionAttribute
and want multilingual support, you need to use resource files anyway.
Usually, I would have one class to get values (displayed name) per enum
type that need to be displayed and one unit test file per resource file although I have some other classes for some common code like comparing key in resource file with value in enum
for unit test (and one overload allows to specify exception).
By the way, in a case like that, it could make sense to have the value of an enum
matches the number of months (for ex. TwelveMonths = 12
). In such case, you can also use string.Format
for displayed values and also have exceptions in resource (like singular).
Upvotes: 0
Reputation: 2341
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];
or
public enum occupancyTimeline
{
TwelveMonths,
FourteenMonths,
SixteenMonths,
EighteenMonths
}
public string[] enumString = {
"12 Months", "14 Months", "16 Months", "18 Months"};
string selectedEnum = enumString[DropDownList.SelectedIndex];
Upvotes: 0