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

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

 model.Item,Model.ItemList) %> 

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

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

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

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

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

 public class RadioButtonListViewModel { 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> listItems; public List> ListItems { get { return listItems; } set { listItems = value; UpdatedSelectedItems(); } } } public class RadioButtonListItem { 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(this HtmlHelper htmlHelper, Expression>> expression) where TModel : class { return htmlHelper.RadioButtonListFor(expression, null); } public static string RadioButtonListFor(this HtmlHelper htmlHelper, Expression>> expression, object htmlAttributes) where TModel : class { return htmlHelper.RadioButtonListFor(expression, new RouteValueDictionary(htmlAttributes)); } public static string RadioButtonListFor(this HtmlHelper htmlHelper, Expression>> expression, IDictionary htmlAttributes) where TModel : class { var inputName = GetInputName(expression); RadioButtonListViewModel 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(Expression> 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 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("
"); return sb.ToString(); } public static string RadioButtonLabel(string inputId, string displayText, IDictionary 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(HtmlHelper htmlHelper, Expression> expression) where TModel : class { TModel model = htmlHelper.ViewData.Model; if (model == null) { return default(TProperty); } Func func = expression.Compile(); return func(model); } }

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

Посмотреть

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

Модель

 public class aTest { public Int32 ID { get; set; } public String Name { get; set; } } public class LogOnModel { public IEnumerable TestRadioList { get; set; } [Required(ErrorMessage="Test Error")] public String TestRadio { get; set; } [Required] [Display(Name = "User name")] public string UserName { get; set; } } 

Действия controllerа

 public ActionResult LogOn() { List list = new List(); 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 list = new List(); 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( this HtmlHelper htmlHelper, Expression> expression, IEnumerable 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( " {2}", id, HttpUtility.HtmlEncode(item.Text), radio ); } } return MvcHtmlString.Create(sb.ToString()); } } 

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

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

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

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

 public static MvcHtmlString InputFor(this HtmlHelper helper, Expression> field, Dictionary 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 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(); 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(this HtmlHelper helper, Expression> field) where TModel : class { string property_name = GetInputName(field) + "List"; PropertyDescriptor list_descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true); Dictionary 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)temp.GetValue(helper.ViewData.Model, null); } return InputFor(helper, field, listing); } 

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

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

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

сойка

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

 public static MvcHtmlString RadioButtonListFor( this HtmlHelper htmlHelper, Expression> expression, IEnumerable listOfValues, IDictionary 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 // eg  ulTag.InnerHtml += string.Format("
  • {0}{1}
  • ", radio, label); } } return MvcHtmlString.Create(ulTag.ToString(TagRenderMode.Normal)); } public static MvcHtmlString RadioButtonListFor( this HtmlHelper htmlHelper, Expression> expression, IEnumerable listOfValues, object radioHtmlAttributes = null, string ulClass = null) { return RadioButtonListFor(htmlHelper, expression, listOfValues, new RouteValueDictionary(radioHtmlAttributes), ulClass); }

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

      public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable _items, string _selectedValue, string _seperator) { return RadioButtonList2(_helper, _name, _items, _selectedValue, _seperator, null); } public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable _items, string _selectedValue, string _seperator, IDictionary _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's checked if (item.Value == _selectedValue) optionField.MergeAttribute("checked", "checked"); if (_htmlAttributes != null) optionField.MergeAttributes(_htmlAttributes); _outputScript.Append(optionField.ToString(TagRenderMode.SelfClosing)); _outputScript.Append("" + _seperator); } return _outputScript.ToString(); } 

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

      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(), " ")%> 

    Вы также можете заменить   с помощью <
    чтобы отобразить их в отдельных строках.

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

    С уважением, Naweed Akram [email protected]

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

      _ 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("", name, item.Value, If(item.Value = value.ToString, """checked""", "")) sb.AppendFormat("", name, item.Value, item.Text) Next divTag.InnerHtml = sb.ToString Return MvcHtmlString.Create(divTag.ToString) End Function 

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

    введите описание изображения здесь

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

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

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

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

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

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

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

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

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

          

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

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

    Вот class помощников:

     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 listItems; public List 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's Id or Name on this. ie for tagBase="GenderRadiosForRoomCreate"      */ public static string RadioButtonListFor(this HtmlHelper htmlHelper, Expression> expression, String tagBase) where TModel : class { return htmlHelper.RadioButtonListFor(expression, tagBase, null); } public static string RadioButtonListFor(this HtmlHelper htmlHelper, Expression> expression, String tagBase, object htmlAttributes) where TModel : class { return htmlHelper.RadioButtonListFor(expression, tagBase, new RouteValueDictionary(htmlAttributes)); } public static string RadioButtonListFor(this HtmlHelper htmlHelper, Expression> expression, String tagBase, IDictionary 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 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 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(HtmlHelper htmlHelper, Expression> expression) where TModel : class { TModel model = htmlHelper.ViewData.Model; if (model == null) { return default(TProperty); } Func func = expression.Compile(); return func(model); } } 
  • Для чего нужны файлы Web.Debug.config и Web.Release.Config?
  • Как реализовать правильную обработку ошибок HTTP в .NET MVC 2?
  • Entity Framework 4 CTP 4 / CTP 5 Общий шаблон хранилища и единица тестирования
  • Каков наилучший вариант для транскрипции речи в текст в веб-приложении asp.net?
  • ASP.NET MVC - получение имени текущей области в представлении или controllerе
  • Проблемы с выбором значений в ListBoxFor
  • Firefox 6 Бесконечная страница обновляется с помощью страницы с тегами hashа
  • Не удается получить sql server compact 3.5 / 4 для работы с ASP.NET MVC 2
  • Когда `PostAuthenticateRequest` получает выполнение?
  • Проверка: как ввести оболочку State Model с помощью Ninject?
  • RegularExpressionAttribute - Как сделать это не чувствительным к регистру для проверки на стороне клиента?
  • Давайте будем гением компьютера.