user979331
user979331

Reputation: 11861

Enum with integer strings

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

Answers (11)

ageroh
ageroh

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

ebattulga
ebattulga

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

Monah
Monah

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

Tom Gullen
Tom Gullen

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

Salah Akbari
Salah Akbari

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

Tomas Kubes
Tomas Kubes

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

Jibin Balachandran
Jibin Balachandran

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

Jure
Jure

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

Tony Dong
Tony Dong

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

Phil1970
Phil1970

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

Shannon Holsinger
Shannon Holsinger

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

Related Questions