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.
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)
{
foreach (SelectListItem item in listOfValues)
{
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
sb.AppendFormat("<div class=\"RadioButton\">{0}{1}</div>", radio, label);
}
}
return MvcHtmlString.Create(sb.ToString());
}
}
}
And here is my updated code.
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)
{
foreach (SelectListItem item in listOfValues)
{
var id = string.Format("rb_{0}_{1}",
fullName.Replace("[", "").Replace(
"]", "").Replace(".", "_"), item.Value);
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButton(fullName, item.Value, item.Selected, new { id = id }).ToHtmlString();
/ name="TestRadio" type="radio"
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.