Кто-нибудь реализует RadioButtonListFor <T> для ASP.NET MVC?

В ASP.NET MVC Futures существовал метод расширения Html.RadioButtonList. Кто-нибудь нашел код для строго типизированной версии RadioButtonListFor<T>. Это выглядело бы так:

<%= Html.RadioButtonListFor(model=>model.Item,Model.ItemList) %>

Ответ 1

Вот использование на странице aspx

    <%= Html.RadioButtonListFor(m => m.GenderRadioButtonList)%>

Вот модель представления

public class HomePageViewModel
{
    public enum GenderType
    {
        Male,
        Female
    }
    public RadioButtonListViewModel<GenderType> GenderRadioButtonList { get; set; }

    public HomePageViewModel()
    {
        GenderRadioButtonList = new RadioButtonListViewModel<GenderType>
        {
            Id = "Gender",
            SelectedValue = GenderType.Male,
            ListItems = new List<RadioButtonListItem<GenderType>>
            {
                new RadioButtonListItem<GenderType>{Text = "Male", Value = GenderType.Male},
                new RadioButtonListItem<GenderType>{Text = "Female", Value = GenderType.Female}
            }
        };
    }
}

Здесь модель представления, используемая для списков переключателей

public class RadioButtonListViewModel<T>
{
    public string Id { get; set; }
    private T selectedValue;
    public T SelectedValue
    {
        get { return selectedValue; }
        set
        {
            selectedValue = value;
            UpdatedSelectedItems();
        }
    }

    private void UpdatedSelectedItems()
    {
        if (ListItems == null)
            return;

        ListItems.ForEach(li => li.Selected = Equals(li.Value, SelectedValue));
    }

    private List<RadioButtonListItem<T>> listItems;
    public List<RadioButtonListItem<T>> ListItems
    {
        get { return listItems; }
        set
        {
            listItems = value;
            UpdatedSelectedItems();
        }
    }
}

public class RadioButtonListItem<T>
{
    public bool Selected { get; set; }

    public string Text { get; set; }

    public T Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

Здесь методы расширения для RadioButtonListFor

public static class HtmlHelperExtensions
{
    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, null);
    }

    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, object htmlAttributes) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, new RouteValueDictionary(htmlAttributes));
    }

    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, IDictionary<string, object> htmlAttributes) where TModel : class
    {
        var inputName = GetInputName(expression);

        RadioButtonListViewModel<TRadioButtonListValue> radioButtonList = GetValue(htmlHelper, expression);

        if (radioButtonList == null)
            return String.Empty;

        if (radioButtonList.ListItems == null)
            return String.Empty;

        var divTag = new TagBuilder("div");
        divTag.MergeAttribute("id", inputName);
        divTag.MergeAttribute("class", "radio");
        foreach (var item in radioButtonList.ListItems)
        {
            var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem{Text=item.Text, Selected = item.Selected, Value = item.Value.ToString()}, htmlAttributes);

            divTag.InnerHtml += radioButtonTag;
        }

        return divTag + htmlHelper.ValidationMessage(inputName, "*");
    }

    public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            var methodCallExpression = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...

        var methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

    public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
                         IDictionary<string, object> htmlAttributes)
    {
        var inputIdSb = new StringBuilder();
        inputIdSb.Append(name)
            .Append("_")
            .Append(listItem.Value);

        var sb = new StringBuilder();

        var builder = new TagBuilder("input");
        if (listItem.Selected) builder.MergeAttribute("checked", "checked");
        builder.MergeAttribute("type", "radio");
        builder.MergeAttribute("value", listItem.Value);
        builder.MergeAttribute("id", inputIdSb.ToString());
        builder.MergeAttribute("name", name + ".SelectedValue");
        builder.MergeAttributes(htmlAttributes);
        sb.Append(builder.ToString(TagRenderMode.SelfClosing));
        sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
        sb.Append("<br>");

        return sb.ToString();
    }

    public static string RadioButtonLabel(string inputId, string displayText,
                                 IDictionary<string, object> htmlAttributes)
    {
        var labelBuilder = new TagBuilder("label");
        labelBuilder.MergeAttribute("for", inputId);
        labelBuilder.MergeAttributes(htmlAttributes);
        labelBuilder.InnerHtml = displayText;

        return labelBuilder.ToString(TagRenderMode.Normal);
    }


    public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
    {
        TModel model = htmlHelper.ViewData.Model;
        if (model == null)
        {
            return default(TProperty);
        }
        Func<TModel, TProperty> func = expression.Compile();
        return func(model);
    }
}

Ответ 2

Пример MVC 3, который создает 3 переключателя с проверкой, чтобы обеспечить выбор 1 опции. И если форма не проходит проверку (например, в других полях), выбранная радио опция предварительно выбирается при изменении формы.

Просмотр

@Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList)
@Html.ValidationMessageFor(m => m.TestRadio)

Model

public class aTest
{
    public Int32 ID { get; set; }
    public String Name { get; set; }
}

public class LogOnModel
{
    public IEnumerable<SelectListItem> TestRadioList { get; set; }

    [Required(ErrorMessage="Test Error")]
    public String TestRadio { get; set; }

    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }
}

Действия с контроллером

public ActionResult LogOn()
    {
        List<aTest> list = new List<aTest>();
        list.Add(new aTest() { ID = 1, Name = "Line1" });
        list.Add(new aTest() { ID = 2, Name = "Line2" });
        list.Add(new aTest() { ID = 3, Name = "Line3" });

        SelectList sl = new SelectList(list, "ID", "Name");

        var model = new LogOnModel();
        model.TestRadioList = sl;

        return View(model);
    }

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
             ....
        }

        // If we got this far, something failed, redisplay form
        List<aTest> list = new List<aTest>();
        list.Add(new aTest() { ID = 1, Name = "Line1" });
        list.Add(new aTest() { ID = 2, Name = "Line2" });
        list.Add(new aTest() { ID = 3, Name = "Line3" });

        SelectList sl = new SelectList(list, "ID", "Name");
        model.TestRadioList = sl;

        return View(model);
    }

Вот расширение:

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 radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
                sb.AppendFormat(
                    "<label for=\"{0}\">{1}</label> {2}",
                    id,
                    HttpUtility.HtmlEncode(item.Text),
                    radio
                );
            }
        }

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

Ответ 3

Хорошо, я знаю, что это не прямой ответ на ваш вопрос, но это может быть лучшим способом сделать большинство входных данных в любом случае (и это было забавно сделать). Я только что закончил это и проверил небольшое количество тестов против него, поэтому я не могу ручаться за то, что это прекрасно в любой ситуации.

Я получил эту идею из сообщения Джимми Богарда здесь. Взгляните, потому что там куча действительно классных идей.

Что я сделал, создается помощник "InputFor", который изо всех сил пытается определить, какой вход вы запрашиваете, и выводит его соответствующим образом. Это будет делать радиокнопки, но по умолчанию будет выпадать, если их больше двух, вы можете легко изменить эту функцию.

В приведенном ниже коде вы можете совершать вызовы, такие как <%= Html.InputFor(m => m.Gender) %> или <%Html.InputFor(m => m.Gender, Model.GenderList)%>. В конце есть прохладный бит, который позволяет вам делать кодирование по соглашению, но мы это доведем позже.

public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field, Dictionary<string, string> listing) where TModel : class
        {
            string property_name = GetInputName(field);
            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
            string property_type = descriptor.PropertyType.Name;
            var func = field.Compile();
            var value = func(helper.ViewData.Model);

            //Add hidden element if required
            if (descriptor.Attributes.Contains(new HiddenInputAttribute()))
            {
                return helper.Hidden(property_name, value);
            }

            if (property_type == "DateTime" || property_type == "Date")
            {
                return helper.TextBox(property_name, value, new { @class = "date_picker" });
            }
            if (listing != null)
            {
                if (listing.Count <= 2)
                {
                    //This is a good length for a radio button
                    string output = "";
                    foreach (KeyValuePair<string, string> pair in listing)
                    {
                        TagBuilder label = new TagBuilder("label");
                        label.MergeAttribute("for", property_name);
                        label.SetInnerText(pair.Value);
                        output += helper.RadioButton(property_name, pair.Key, (value == pair.Key)).ToHtmlString();
                        output += label.ToString();
                    }
                    return MvcHtmlString.Create(output);
                }
                else
                {
                    //too big for a radio button, lets make a drop down
                    return helper.DropDownList(property_name, new SelectList(listing, "Key", "Value"), value);
                }
            }
            else
            {
                if (property_type == "Boolean")
                {
                    listing = new Dictionary<string, string>();
                    listing.Add("true", "Yes");
                    listing.Add("false", "No");
                    SelectList select_values = new SelectList(listing, "Key", "Value", ((bool)value ? "Yes" : "No"));
                    return helper.DropDownList(property_name, select_values);
                }
                return helper.TextBox(property_name, value);
            }
        }

Кодирование по Конвенции

В приведенном ниже коде это можно сделать с учетом соглашения о конфигурации. Например, если у вас есть объект модели, который содержит свойство, которое вы хотите перечислить (Пол), и словарь с тем же именем, но добавленный с помощью "Список" (GenderList), то он будет использовать этот список по умолчанию.

например. <%= Html.InputFor(m => m.Gender) %> может создать полный список выпадающих списков/группу переключателей, но эти значения по умолчанию можно переопределить, совершив вызов типа <%= Html.InputFor(m => m.Gender, alternate_list) %>

public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field) where TModel : class
{
    string property_name = GetInputName(field) + "List";
    PropertyDescriptor list_descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
    Dictionary<string, string> listing = null;

    if (list_descriptor != null)
    {
        //Found a match for PropertyNameList, try to pull it out so we can use it
        PropertyInfo temp = helper.ViewData.Model.GetType().GetProperty(property_name);
        listing = (Dictionary<string, string>)temp.GetValue(helper.ViewData.Model, null);
    }
    return InputFor(helper, field, listing);
}

Теперь небольшая оговорка:

  • Это не самый быстрый код в мире (из-за отражения и других вещей), в моей ситуации это не очень актуально, поскольку все это управляется пользователем, если вы планируете делать что-то сумасшедшее глупо.
  • Этот код находится в зачаточном состоянии, я буду тестировать его более тщательно и добавлю к нему в течение следующих нескольких дней, открывая любые предложения по улучшению кода.

Я надеюсь, что этот код полезен кому-то, я знаю, что буду использовать его в течение следующих нескольких недель, чтобы попытаться сократить время. Сокращение этого, чтобы просто сделать переключатель, должно быть тривиальной задачей, удачи:)

Джей

Ответ 4

Основанный на Jon post, небольшое улучшение для создания списка переключателей в виде ul с помощью HTMLAttributtes

public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues,
        IDictionary<string, object> radioHtmlAttributes = null,
        string ulClass = null)
    {
        ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        if (radioHtmlAttributes == null)
            radioHtmlAttributes = new RouteValueDictionary();

        TagBuilder ulTag = new TagBuilder("ul");
        if (!String.IsNullOrEmpty(ulClass))
            ulTag.MergeAttribute("class", ulClass);

        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);

                if (!radioHtmlAttributes.ContainsKey("id"))
                    radioHtmlAttributes.Add("id", id);
                else
                    radioHtmlAttributes["id"] = id;

                // 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, radioHtmlAttributes).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> 
                ulTag.InnerHtml += string.Format("<li>{0}{1}</li>", radio, label);
            }
        }

        return MvcHtmlString.Create(ulTag.ToString(TagRenderMode.Normal));
    }

    public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues,
        object radioHtmlAttributes = null,
        string ulClass = null)
    {
        return RadioButtonListFor<TModel, TProperty>(htmlHelper, expression, listOfValues, new RouteValueDictionary(radioHtmlAttributes), ulClass);
    }

Ответ 5

Я реализовал нечто подобное в MVC 1.0. Посмотрите, поможет ли это вам:

    public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator)
    {
        return RadioButtonList2(_helper, _name, _items, _selectedValue, _seperator, null);
    }

    public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator, IDictionary<string, object> _htmlAttributes)
    {
        StringBuilder _outputScript = new StringBuilder();

        foreach (var item in _items)
        {
            var optionField = new TagBuilder("input");
            optionField.MergeAttribute("name", _name);
            optionField.MergeAttribute("id", _name);
            optionField.MergeAttribute("class", _name);
            optionField.MergeAttribute("value", item.Value);
            optionField.MergeAttribute("type", "radio");

            // Check to see if it checked
            if (item.Value == _selectedValue)
                optionField.MergeAttribute("checked", "checked");

            if (_htmlAttributes != null)
                optionField.MergeAttributes(_htmlAttributes);

            _outputScript.Append(optionField.ToString(TagRenderMode.SelfClosing));
            _outputScript.Append("<label style=\"display:inline;\">");
            _outputScript.Append(item.Text);
            _outputScript.Append("</label>" + _seperator);
        }

        return _outputScript.ToString();
    }

В контроллере вы можете вернуть результат следующим образом:

        ViewData["GenderList"] = new SelectList(new[] { new { Value = "M", Text = "Male" }, new { Value = "F", Text = "Female" }, new { Value = "A", Text = "All" } }, "Value", "Text");

или

        ViewData["GenderList"] = new SelectList(_resultFromSomeLinqQuery, "GenderID", "GenderName");

И используйте его в представлении следующим образом:

<%= Html.RadioButtonList2("Sex", ViewData["GenderList"] as SelectList, ViewData["SelectedSex"].ToString(), "&nbsp;")%>

Вы также можете заменить &nbsp; на <BR />, чтобы отобразить их в отдельных строках.

Надеюсь, что это поможет.

Отношения Naweed Akram [email protected]

Ответ 6

Вот маленький "тонкий" ответ в хорошем ol VB. Работает для меня, но это не полное решение.

<Extension()> _
Public Function RadioButtonListFor(Of TModel, TProperty)(ByVal htmlHelper As System.Web.Mvc.HtmlHelper(Of TModel), ByVal expression As System.Linq.Expressions.Expression(Of System.Func(Of TModel, TProperty)), ByVal selectList As System.Collections.Generic.IEnumerable(Of System.Web.Mvc.SelectListItem), ByVal htmlAttributes As Object) As System.Web.Mvc.MvcHtmlString
    'Return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes)
    If selectList Is Nothing OrElse selectList.Count = 0 Then Return MvcHtmlString.Empty

    Dim divTag = New TagBuilder("div")
    divTag.MergeAttributes(New RouteValueDictionary(htmlAttributes))
    Dim name = CType(expression.Body, System.Linq.Expressions.MemberExpression).Member.Name
    Dim value = expression.Compile()(htmlHelper.ViewData.Model)
    Dim sb As New StringBuilder()

    For Each item In selectList
        sb.AppendFormat("<input id=""{0}_{1}"" type=""radio"" name=""{0}"" value=""{1}"" {2} />", name, item.Value, If(item.Value = value.ToString, """checked""", ""))
        sb.AppendFormat("<label for=""{0}_{1}"">{2}</label>", name, item.Value, item.Text)
    Next

    divTag.InnerHtml = sb.ToString

    Return MvcHtmlString.Create(divTag.ToString)

End Function

Ответ 7

Я изменил решение Mac и заменил тип Enum по таблице базы данных, моя таблица:

enter image description here

В моем заявлении я арендую комнату в соответствии с гендерными предпочтениями. Моя модель с свойством GenderRadios:

public partial class Room
{
 public RadioButtonListViewModel GenderRadios { get; set; }
 //...
}

В комнатном контроллере я готовлю радиостанции:

   private void fillRadios(Room room)
    {         
        List<Gender> genders = fre.Genders.ToList();
        room.GenderRadios= new RadioButtonListViewModel();
        room.GenderRadios.ListItems = new List<RadioButtonListItem>();
        foreach (Gender gender in genders)
            room.GenderRadios.ListItems.Add(new RadioButtonListItem { Text = gender.Name, Value = gender.Id, Selected= (room.GenderId == gender.Id)});
    }

Наконец, я использую его в представлении для создания комнаты:

<tr> 
<td>Gender</td>
   <%= Html.RadioButtonListFor(m => m.GenderRadios, "GenderRadiosForRoomCreate")%>         
</tr>

и для редактирования комнаты:

<tr> 
<td>Gender</td>
    <%= Html.RadioButtonListFor(m => m.GenderRadios, "GenderRadiosForRoomEdit")%>         
</tr>

Создать html комнаты будет выглядеть так:

<td id="GenderRadisoForRoomCreate_Container">
<input id="GenderRadisoForRoomCreate_Any" name="GenderRadisoForRoomCreate_value" value="1" type="radio"><label for="GenderRadisoForRoomCreate_Any">Any</label>
<input id="GenderRadisoForRoomCreate_Female" name="GenderRadisoForRoomCreate_value" value="2" type="radio"><label for="GenderRadisoForRoomCreate_Female">Female</label>
<input id="GenderRadisoForRoomCreate_Male" name="GenderRadisoForRoomCreate_value" value="3" type="radio"><label for="GenderRadisoForRoomCreate_Male">Male</label>
</td>

Когда комната создана:

[HttpPost]
public ActionResult RoomCreate(Room room, FormCollection formValues, int? GenderRadiosForRoomCreate_value, int? SmokingRadiosForRoomCreate_value)
{
    room.GenderId = GenderRadiosForRoomCreate_value;
    room.SmokingId = SmokingRadiosForRoomCreate_value;
//...
}

Вот класс помощников:

public class RadioButtonListViewModel
{
    public int Id { get; set; }

    private int selectedValue;
    public int SelectedValue
    {
        get { return selectedValue; }
        set
        {
            selectedValue = value;
            UpdatedSelectedItems();
        }
    }

    private void UpdatedSelectedItems()
    {
        if (ListItems == null)
            return;

        ListItems.ForEach(li => li.Selected = Equals(li.Value, SelectedValue));
    }

    private List<RadioButtonListItem> listItems;
    public List<RadioButtonListItem> ListItems
    {
        get { return listItems; }
        set
        {
            listItems = value;
            UpdatedSelectedItems();
        }
    }
}

public class RadioButtonListItem
{
    public bool Selected { get; set; }

    public string Text { get; set; }



    public int Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}



public static class HtmlHelperExtensions
{
    /* 
     tagBase: I used tagBase string for building other tag Id or Name on this. i.e. for tagBase="GenderRadiosForRoomCreate" 
        <td id="GenderRadisoForRoomCreate_Container">
        <input id="GenderRadisoForRoomCreate_Any" name="GenderRadisoForRoomCreate_value" value="1" type="radio"><label for="GenderRadisoForRoomCreate_Any">Any</label>
        <input id="GenderRadisoForRoomCreate_Female" name="GenderRadisoForRoomCreate_value" value="2" type="radio"><label for="GenderRadisoForRoomCreate_Female">Female</label>
        <input id="GenderRadisoForRoomCreate_Male" name="GenderRadisoForRoomCreate_value" value="3" type="radio"><label for="GenderRadisoForRoomCreate_Male">Male</label>
        </td>     
    */
    public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, tagBase, null);
    }

    public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase, object htmlAttributes) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, tagBase, new RouteValueDictionary(htmlAttributes));
    }

    public static string RadioButtonListFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel>> expression, String tagBase, IDictionary<string, object> htmlAttributes) where TModel : class
    {        
        var inputName = tagBase;
        RadioButtonListViewModel radioButtonList = GetValue(htmlHelper, expression);

        if (radioButtonList == null)
            return String.Empty;

        if (radioButtonList.ListItems == null)
            return String.Empty;


        var containerTag = new TagBuilder("td");
        containerTag.MergeAttribute("id", inputName + "_Container");                
        foreach (var item in radioButtonList.ListItems)
        {
            var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem{Text=item.Text, Selected = item.Selected, Value = item.Value.ToString()}, htmlAttributes);

            containerTag.InnerHtml += radioButtonTag;
        }

        return containerTag.ToString();
    }

    public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
                         IDictionary<string, object> htmlAttributes)
    {
        var inputIdSb = new StringBuilder();
        inputIdSb.Append(name);

        var sb = new StringBuilder();

        var builder = new TagBuilder("input");
        if (listItem.Selected) builder.MergeAttribute("checked", "checked");
        builder.MergeAttribute("type", "radio");
        builder.MergeAttribute("value", listItem.Value);
        builder.MergeAttribute("id", inputIdSb.ToString() + "_" + listItem.Text);    
        builder.MergeAttribute("name", name + "_value");
        builder.MergeAttributes(htmlAttributes);
        sb.Append(builder.ToString(TagRenderMode.SelfClosing));
        sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
        return sb.ToString();
    }

    public static string RadioButtonLabel(string inputId, string displayText,
                                 IDictionary<string, object> htmlAttributes)
    {
        var labelBuilder = new TagBuilder("label");
        labelBuilder.MergeAttribute("for", inputId + "_" + displayText);
        labelBuilder.MergeAttributes(htmlAttributes);
        labelBuilder.InnerHtml = displayText;

        return labelBuilder.ToString(TagRenderMode.Normal);
    }


    public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
    {
        TModel model = htmlHelper.ViewData.Model;
        if (model == null)
        {
            return default(TProperty);
        }
        Func<TModel, TProperty> func = expression.Compile();
        return func(model);
    }
}