Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

MVC Enum RadioButtonList Helper

5.00/5 (3 votes)
14 Jun 2012CPOL 54.7K  
An MVC Razor Helper to generate radio button lists from enums

Introduction

I came across a problem where I would like to use a Radio Button List for selecting an Enumeration value. I found a nice little example online by Jon Lanceley here but found it to be missing a couple of features. So... as all developers do, we tinker and add.

The Code

I'll include both sets of code so that you can see the difference. 

Here is the original block of code that Jon published.  

C#
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Mvc.Html; 
using System.Linq.Expressions; 
using System.Text;
namespace MVC3_RadioButtonList_Helper_Sample 
{ 
    public static class HtmlExtensions 
    { 
        public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>( 
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            IEnumerable<SelectListItem> listOfValues) 
        { 
            var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 
            var sb = new StringBuilder();
            if (listOfValues != null) 
            { 
                // Create a radio button for each item in the list 
                foreach (SelectListItem item in listOfValues) 
                { 
                    // Generate an id to be given to the radio button field 
                    var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
                    // Create and populate a radio button using the existing html helpers 
                    var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text)); 
                    var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
                    // Create the html string that will be returned to the client 
                    // e.g. <input data-val="true" data-val-required=
                    //   "You must select an option" id="TestRadio_1" 
                    //   name="TestRadio" type="radio" 
                    //   value="1" /><label for="TestRadio_1">Line1</label> 
                    sb.AppendFormat("<div class=\"RadioButton\">{0}{1}</div>", radio, label); 
                } 
            }
            return MvcHtmlString.Create(sb.ToString()); 
        } 
    } 
}

And here is my updated code. 

C#
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Mvc.Html; 
using System.Linq.Expressions; 
using System.Text;

namespace MVC3_RadioButtonList_Helper_Sample 
{ 
    public static class HtmlExtensions 
    { 
        public static IEnumerable<SelectListItem> ToSelectList(this Enum enumValue)
        {
            return from Enum e in Enum.GetValues(enumValue.GetType())
                   select new SelectListItem
                   {
                       Selected = e.Equals(enumValue),
                       Text = e.ToDescription(),
                       Value = e.ToString()
                   };
        }

        public static string ToDescription(this Enum value)
        {
            var attributes = (DescriptionAttribute[])value.GetType().GetField(
              value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : value.ToString();
        }

        public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            IEnumerable<SelectListItem> listOfValues, Position position = Position.Horizontal)
        {
            var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            string fullName = ExpressionHelper.GetExpressionText(expression);
            var sb = new StringBuilder();

            if (listOfValues != null)
            {
                // Create a radio button for each item in the list 
                foreach (SelectListItem item in listOfValues)
                {
                    // Generate an id to be given to the radio button field 
                    var id = string.Format("rb_{0}_{1}", 
                      fullName.Replace("[", "").Replace(
                      "]", "").Replace(".", "_"), item.Value);
                    
                    // Create and populate a radio button using the existing html helpers 
                    var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
                    //var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
                    var radio = htmlHelper.RadioButton(fullName, item.Value, item.Selected, new { id = id }).ToHtmlString();

                    // Create the html string that will be returned to the client 
                    // e.g. <input data-val="true" data-val-required=
                    //   "You must select an option" id="TestRadio_1" 
                    /    name="TestRadio" type="radio"
                    //   value="1" /><label for="TestRadio_1">Line1</label> 
                    sb.AppendFormat("<{2} class=\"RadioButton\">{0}{1}</{2}>", 
                       radio, label, (position == Position.Horizontal ? "span" : "div"));
                }
            }

            return MvcHtmlString.Create(sb.ToString());
        } 
    }
}

The differences 

His code was pretty good but missed a couple of things. The first was an easy way to generate the actual list of items. The second was that he didn't account for models that contained an indexer in its parentage. Using the helper methods fixes the first one and using the same method Microsoft uses to find the full name of the property fixes the second. Adding the "rb_" to the front of the id's ensures that the id name is always legal. 

Hope this is helpful and thanks to Jon for a pretty good helper method to start from. 

History

Initial publication.

License

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