¿Cómo crear un método de extensión CheckBoxListFor en ASP.NET MVC?

Sé que hay un método de extensión ListBoxFor entre los métodos de extensión de ayuda de ASP.NET MVC Html, pero siempre pensé que una lista de casillas de verificación es más fácil de usar que un cuadro de lista.

Había un control CheckBoxList muy conveniente en los viejos WebForms antiguos, pero obviamente ahora está fuera de lugar.

La pregunta es, ¿por qué no hay forma en ASP.NET MVC de crear una lista de checkbox? ¿Cómo puedo escribir mi propio método de extensión que crea una lista de checkbox y se comporta de manera similar a ListBoxFor ?

Aquí hay un HtmlHelper fuertemente tipado para CheckBoxListFor que maneja los elementos seleccionados como una matriz en su modelo de viewdata. Elegí no envolver los métodos Html.CheckBox o Html.CheckBoxFor ya que no quiero los campos “falsos” ocultos en mi lista de casillas de verificación.

Por favor, siéntete libre de mejorar esto y volver a publicar 🙂

 //View <%: Html.CheckBoxListFor(model => model.FreightTypeIds, FreightTypeMultiSelectList) %> //Controller public ActionResult SomeAction(int[] FreightTypeIds) { //... return View(); } //Extension public static MvcHtmlString CheckBoxListFor(this HtmlHelper htmlHelper, Expression>> expression, MultiSelectList allOptions, object htmlAttributes = null) { ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression>(expression, htmlHelper.ViewData); // Derive property name for checkbox name string propertyName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(modelMetadata.PropertyName); // Get currently select values from the ViewData model IEnumerable list = expression.Compile().Invoke(htmlHelper.ViewData.Model); // Convert selected value list to a List for easy manipulation IList selectedValues = new List(); if (list != null) { selectedValues = new List(list).ConvertAll(delegate(TProperty i) { return i.ToString(); }); } // Create div TagBuilder divTag = new TagBuilder("div"); divTag.MergeAttributes(new RouteValueDictionary(htmlAttributes), true); // Add checkboxes foreach (SelectListItem item in allOptions) { divTag.InnerHtml += string.Format( "
", propertyName, TagBuilder.CreateSanitizedId(propertyName), item.Value, selectedValues.Contains(item.Value) ? "checked=\"checked\"" : string.Empty, item.Text); } return MvcHtmlString.Create(divTag.ToString()); }

Todavía estoy experimentando, pero parece que se lleva bien con la carpeta predeterminada y persiste en las selecciones del usuario después de la publicación … ¿Campos ocultos, en realidad? ¿volará esto en html5? Esto parece una locura, pero preferiría hacer esto antes que pegarle a mi DB por listas desplegables y listas de casillas simplemente porque ModelState.IsValid es falso.

  public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, List list, string ModelCollectionName) { var sb = new StringBuilder(); if (list != null) { int i = 0; foreach (var l in list) { string collectionNameIndex = String.Format("{0}[{1}]", ModelCollectionName, i); var hiddenName = new TagBuilder("input"); hiddenName.Attributes.Add(new KeyValuePair("type", "hidden")); hiddenName.Attributes.Add(new KeyValuePair("name", String.Format("{0}.{1}", collectionNameIndex, "Text"))); hiddenName.Attributes.Add(new KeyValuePair("value", l.Text)); var hiddenValue = new TagBuilder("input"); hiddenValue.Attributes.Add(new KeyValuePair("type", "hidden")); hiddenValue.Attributes.Add(new KeyValuePair("name", String.Format("{0}.{1}", collectionNameIndex, "Value"))); hiddenValue.Attributes.Add(new KeyValuePair("value", l.Value)); var checkBoxTag = htmlHelper.CheckBox(String.Format("{0}.{1}", collectionNameIndex, "Selected"), l.Selected); var labelTag = new TagBuilder("label"); labelTag.Attributes.Add(new KeyValuePair("for", String.Format("{0}.{1}", collectionNameIndex, "Name"))); labelTag.SetInnerText(l.Text); sb.Append(hiddenName); sb.Append(hiddenValue); sb.Append(checkBoxTag); sb.Append(labelTag); sb.Append("
"); i++; } } return MvcHtmlString.Create(sb.ToString()); }

Si bien los empleados de Microsoft son probablemente los únicos que pueden responder por qué dicho método auxiliar no existe, podría intentar:

Modelo:

 public class MyViewModel { public bool[] Values { get; set; } } 

Controlador:

 public class HomeController : Controller { public ActionResult Index() { return View(new MyViewModel { Values = new[] { true, false, true, false } }); } [HttpPost] public ActionResult Index(MyViewModel model) { return View(model); } } 

Ver:

 <% using (Html.BeginForm()) { %> <%: Html.EditorFor(x => x.Values) %>  <% } %> 

Como puede ver, EditorFor manejará todo lo que sea necesario.

Puede que le interese el artículo de CheckBoxList Helper para MVC de Jeremiah Clark (desafortunadamente está fechado en noviembre de 2008 y se refiere a MVC 1).