Qualcuno ha implementato RadioButtonListFor per ASP.NET MVC?

C’era un metodo di estensione Html.RadioButtonList in ASP.NET MVC Futures. Qualcuno ha trovato un codice per una versione fortemente digitata RadioButtonListFor . Sarebbe come questo in una vista:

 model.Item,Model.ItemList) %> 

Ecco l’utilizzo nella pagina di aspx

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

Ecco il modello di vista

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

Ecco il modello di visualizzazione utilizzato per gli elenchi di pulsanti di scelta

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

Ecco i metodi di estensione per 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); } }

Esempio MVC 3 che crea 3 pulsanti radio con convalida per garantire che 1 opzione sia selezionata. E se il modulo fallisce la validazione (ad es. Su altri campi) l’opzione radio selezionata viene preselezionata quando il modulo viene riscritto.

vista

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

Modello

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

Azioni del 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); } 

Ecco l’estensione:

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

Ok, sono consapevole che questa non è una risposta diretta alla tua domanda, ma potrebbe comunque essere un modo migliore di fare la maggior parte degli input (ed è stato divertente farlo). Ho appena completato questo e ho eseguito una piccola quantità di test contro di esso, quindi non posso garantire che questo sia perfetto in ogni situazione.

Ho avuto questa idea dal post di Jimmy Bogard qui . Dai un’occhiata perché c’è un mucchio di idee davvero interessanti lì.

Quello che ho fatto è stato creare un helper “InputFor” che fa del suo meglio per capire quale input si sta richiedendo e lo emette di conseguenza. Questo farà i pulsanti di opzione, ma per impostazione predefinita verrà visualizzato un menu a discesa se ce ne sono più di due, dovresti essere in grado di modificare questa funzionalità abbastanza facilmente.

Il codice sottostante consente di effettuare chiamate come <%= Html.InputFor(m => m.Gender) %> o <%Html.InputFor(m => m.Gender, Model.GenderList)%> . Alla fine c’è qualcosa di fresco che ti permette di fare il codice per convenzione, ma ci arriveremo più tardi.

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

Coding by Convention

Il codice sottostante consente di eseguire questa operazione in base alla convenzione sulla configurazione. Un esempio di questo è se si ha un object modello che contiene la proprietà che si desidera elencare (Gender) e un dizionario con lo stesso nome ma aggiunto a “List” (GenderList), quindi utilizzerà questo elenco per impostazione predefinita.

es. <%= Html.InputFor(m => m.Gender) %> può creare un elenco completo a discesa / un gruppo pulsanti radio, ma questi valori predefiniti possono essere sovrascritti effettuando una chiamata come <%= 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); } 

Ora un leggero disclaimer:

  • Questo non è il codice più veloce del mondo (a causa del riflesso e di altre cose), nella mia situazione questo non è veramente rilevante in quanto è tutto guidato dall’utente, se hai intenzione di fare qualcosa di pazzo stupido.
  • Questo codice è nella sua infanzia, lo testerò più approfonditamente e aggiungendolo nei prossimi giorni, aperto a qualsiasi suggerimento per migliorare il codice.

Spero che questo codice sia utile a qualcuno, so che lo userò nelle prossime due settimane per provare a ridurre il tempo. Tagliare questo verso il basso per fare solo il pulsante radio dovrebbe essere un compito banale, buona fortuna 🙂

ghiandaia

Basato su Jon post , un piccolo miglioramento per generare l’elenco dei pulsanti di opzione come ul con 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); }

    Ho implementato qualcosa di simile in MVC 1.0. Verifica se questo ti sarà utile:

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

    Nel controller, è ansible restituire il risultato come segue:

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

    o

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

    E usalo nella vista come segue:

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

    Puoi anche sostituire il   con
    per visualizzarli in linee
    .

    Spero che questo ti aiuti.

    Saluti Naweed Akram [email protected]

    Ecco una risposta un po ‘più snella nel buon vecchio VB. Funziona per me, ma non è una soluzione completa.

      _ 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 

    Ho modificato la soluzione di Mac e sostituito il tipo Enum dalla tabella del database, la mia tabella è:

    inserisci la descrizione dell'immagine qui

    Nella mia domanda sto affittando la stanza secondo le preferenze di genere. Il mio modello con proprietà GenderRadios:

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

    Nel controller della stanza, sto preparando le radio:

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

    infine, lo uso nella vista per creare spazio:

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

    e per la modifica della stanza:

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

    Creare room html sarà simile a:

          

    Quando la stanza è stata creata:

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

    Ecco la class degli helper:

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