Click here to Skip to main content
15,886,137 members
Articles / Web Development / ASP.NET

Bind Enum to DropdownList in ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.75/5 (13 votes)
23 Apr 2016CPOL3 min read 72.4K   19   7
Better approach to bind dropdownlist with enum in MVC

Introduction

Sometimes, we have a scenario during development where we need to populate dropdownlist from Enum. There are a couple of ways to do it. But every way has its pros and cons. One should always keep in mind the SOLID and DRY principle while writing code. I will show two ways to do it and you will be able to understand which one is better and why it is better.

Approach 1 (Typical Way)

The first approach in my point of view is not very elegant, but it will surely do what we want it to.

Consider the following Enum which we want to populate in the drop down:

C#
public enum eUserRole : int
{
   SuperAdmin = 0,
   PhoenixAdmin = 1,
   OfficeAdmin = 2,
   ReportUser = 3,
   BillingUser = 4
 }

So normally, what we do is create SelectList by adding each Enum value in the following way in the action:

C#
var enumData = from eUserRole e in Enum.GetValues(typeof(eUserRole))
               select new
                    {
                      ID = (int)e,
                      Name = e.ToString()
                    };

Now, set it in ViewBag so that we can use it in View:

C#
ViewBag.EnumList = new SelectList(enumData,"ID","Name");

and now in View:

C#
@Html.DropDownList("EnumDropDown",ViewBag.EnumList as SelectList)

Problem in Approach 1

The problem with the above method is that whenever we have Enum to be binded with some Html Helper, we have to write the above Linq query code to get the enum all values in the action which is a bit of a pain to rewrite one thing again and again. We will see next how we can make it better and reusable.

Approach 2

Now, here is an elegant way to achieve it using Extension Method and Generics, which will return Enum values as a SelectList for any type of Enum:

C#
public static class ExtensionMethods
{
     public static System.Web.Mvc.SelectList ToSelectList<TEnum>(this TEnum obj)
         where TEnum : struct, IComparable, IFormattable, IConvertible 
     {

     return new SelectList(Enum.GetValues(typeof(TEnum)).OfType<Enum>()
         .Select(x =>
             new SelectListItem
             {
                 Text = Enum.GetName(typeof(TEnum), x),
                 Value = (Convert.ToInt32(x)).ToString()
             }), "Value", "Text");
     }
 }

and now, we just need to call it on any Enum in action this way:

C#
ViewBag.EnumList = eUserRole.SuperAdmin.ToSelectList();

We can also use it directly in the View, we only have to include namespace in case it's in a separate namespace:

C#
@Html.DropDownList("EnumDropDown",eUserRole.SuperAdmin.ToSelectList())

You will probably need to set the selected value of dropdownlist in the case when user is editing record.

We can extend the extension method according to our requirements.

Overload with Selected Value Parameter

Here is the extension method overload to pass selected value in case we want to set selected value, you can write other overloads as well according to the need:

C#
public static class ExtensionMethods
{
    public static System.Web.Mvc.SelectList ToSelectList<TEnum>(this TEnum obj,object selectedValue)
  where TEnum : struct, IComparable, IFormattable, IConvertible 
    {
    return new SelectList(Enum.GetValues(typeof(TEnum)).OfType<Enum>()
        .Select(x =>
            new SelectListItem
            {
                Text = Enum.GetName(typeof(TEnum), x),
                Value = (Convert.ToInt32(x)).ToString()
            }), "Value", "Text",selectedValue);
    }
}

and usage in View this way:

HTML
@Html.DropDownList("EnumDropDownWithSelected",
  eUserRole.SuperAdmin.ToSelectList((int)eUserRole.OfficeAdmin))

Now the dropdown will have OfficeAdmin selected by default.

In most cases, we don't want to show Enum value in dropdown list instead of that we want to show user friendly term as dropdown text. For that purpose, we can write our Attribute for Enum in the following way:

Create a custom class which inherits from Attribute type:

C#
public class EnumDisplayNameAttribute : Attribute
{
   private string _displayName;
   public string DisplayName
   {
      get { return _displayName; }
      set { _displayName = value; }
   }
 }

and now use attribute on Enum:

C#
public enum eUserRole : int
{
   [EnumDisplayName(DisplayName="Super Admin")]
   SuperAdmin = 0,
   [EnumDisplayName(DisplayName = "Phoenix Admin")]
   PhoenixAdmin = 1,
   [EnumDisplayName(DisplayName = "Office Admin")]
   OfficeAdmin = 2,
   [EnumDisplayName(DisplayName = "Report User")]
   ReportUser = 3,
   [EnumDisplayName(DisplayName = "Billing User")]
   BillingUser = 4
}

Now, we will need to modify or write another extension method as now we need to pick value of DisplayName attribute.

We have two extension methods now, one which returns specific Enum value DisplayName Attribute value and the second which returns SelectList against for Enum:

C#
public static class ExtensionMethods
{
    public static System.Web.Mvc.SelectList ToSelectList<TEnum>(this TEnum obj)
        where TEnum : struct, IComparable, IFormattable, IConvertible // correct one
    {

    return new SelectList(Enum.GetValues(typeof(TEnum)).OfType<Enum>()
        .Select(x =>
            new SelectListItem
            {
                Text = x.DisplayName(),
                Value = (Convert.ToInt32(x)).ToString()
            }), "Value", "Text");
    }

   public static string DisplayName(this Enum value)
   {
       FieldInfo field = value.GetType().GetField(value.ToString());

       EnumDisplayNameAttribute attribute
               = Attribute.GetCustomAttribute(field, typeof(EnumDisplayNameAttribute))
                   as EnumDisplayNameAttribute;

       return attribute == null ? value.ToString() : attribute.DisplayName;
   }
}

Problem with Approach 2

The second approach is much better than the first one, but there is one problem left in approach 2 which is that we have hard coded Attribute type in the extension, it is quite possible that we have multiple Enum attributes and we can have them decorated with different Enums and calling this extension method on those would not work well.

Approach 3

So, I came up with a better implementation so that consumers can pass the attribute type and property of attribute which needs to be used.

We will add another extension method which returns the attribute value and it will be generic so user can specify the attribute type itself:

C#
public static string AttributeValue<TEnum,TAttribute>(this TEnum value,Func<TAttribute,string> func) 
    where T : Attribute
{
   FieldInfo field = value.GetType().GetField(value.ToString());

   T attribute = Attribute.GetCustomAttribute(field, typeof(T)) as T;

   return attribute == null ? value.ToString() : func(attribute);

}  

This extension we will consume inside the extension method which returns Enum as SelectList:

C#
public static System.Web.Mvc.SelectList ToSelectList<TEnum,TAttribute>
(this TEnum obj,Func<TAttribute,string> func,object selectedValue=null)
  where TEnum : struct, IComparable, IFormattable, IConvertible
  where TAttribute : Attribute
    {
        
        return new SelectList(Enum.GetValues(typeof(TEnum)).OfType<Enum>() 
             .Select(x => 
                 new SelectListItem 
                 { 
                    Text = x.AttributeValue<TEnum,TAttribute>(func), 
                    Value = (Convert.ToInt32(x)).ToString() 
                 }), 
             "Value", 
             "Text",
              selectedValue);
    }

and now consumer can use it by passing the attribute and its property which to use for Display name, our View code would now look like:

HTML
 @Html.DropDownList("EnumDropDownWithSelected", eUserRole.SuperAdmin.ToSelectList<eUserRole,
EnumDisplayNameAttribute>(attr=>attr.DisplayName,(int)eUserRole.OfficeAdmin))

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Pakistan Pakistan
Ehsan Sajjad is a Microsoft Certified Professional, Microsoft Certified C# Specialist and he is also among the top users on StackOverflow from Pakistan with 50k+ reputation at time of writing this and counting.

He is a passionate software developer with around 5 years of professional experience in Microsoft Technologies both web and desktop applications and always open to learn new things and platforms especially in mobile application development and game development.

Some Achievements :

  • 5th Top Contributor from Pakistan on Stackoverflow.com
  • Top User in ASP.NET MVC from Pakistan on Stackoverflow.com
  • 21st June 2017 - Article of the Day - ASP.NET Community (Beginners Guide on AJAX CRUD Operations in Grid using JQuery DataTables in ASP.NET MVC 5)
  • 19th April 2017 - Article of the Day - ASP.NET Community (ASP.NET MVC Async File Uploading using JQuery)
  • March 2017 - Visual C# Technical Guru Silver Medal on Microsoft Tech Net Wiki Article Competition
  • 20 January 2017 - Article of the Day - ASP.NET Community (Async File Uploading in ASP.NET MVC)
  • 22nd September 2016 - Article of the Day - ASP.NET Community (GridView with Server Side Filtering, Sorting and Paging in ASP.NET MVC 5)
  • 22nd August 2016 - Article of the Day - ASP.NET Community (Beginners Guide for Creating GridView in ASP.NET MVC 5)
  • December 2015 - C-SharpCorner Monthly Winner

Comments and Discussions

 
QuestionNot just best practice Pin
hellerim17-Nov-15 11:40
professionalhellerim17-Nov-15 11:40 
AnswerRe: Not just best practice Pin
Ehsan Sajjad17-Nov-15 22:54
professionalEhsan Sajjad17-Nov-15 22:54 
QuestionValuable Pin
Member 1117239317-Nov-15 9:48
professionalMember 1117239317-Nov-15 9:48 
AnswerRe: Valuable Pin
Ehsan Sajjad17-Nov-15 10:12
professionalEhsan Sajjad17-Nov-15 10:12 
GeneralMy vote of 5 Pin
Ravi Shankar K16-Nov-15 21:00
Ravi Shankar K16-Nov-15 21:00 
GeneralRe: My vote of 5 Pin
Ehsan Sajjad17-Nov-15 6:36
professionalEhsan Sajjad17-Nov-15 6:36 
GeneralMy Vote of 5 Pin
aarif moh shaikh16-Nov-15 17:48
professionalaarif moh shaikh16-Nov-15 17:48 
GeneralRe: My Vote of 5 Pin
Ehsan Sajjad17-Nov-15 6:36
professionalEhsan Sajjad17-Nov-15 6:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.