2010-10-08 24 views
15

So che esiste un metodo di estensione ListBoxFor tra i metodi di estensione helper ASP.NET MVC Html, ma ho sempre pensato che un elenco di caselle di controllo fosse più intuitivo di una casella di riepilogo.Come creare un metodo di estensione CheckBoxListFor in ASP.NET MVC?

C'era un controllo molto conveniente CheckBoxList nei buoni vecchi WebForms, ma ovviamente questo è fuori scena ora.

La domanda è: perché in ASP.NET MVC non è possibile creare un elenco di caselle di controllo? Come posso scrivere il mio metodo di estensione che crea un elenco di caselle di controllo e si comporta in modo simile allo ListBoxFor?

risposta

33

Ecco un HtmlHelper fortemente tipizzato per CheckBoxListFor che gestisce gli elementi selezionati come una matrice nel modello viewdata. Ho scelto di non eseguire il wrapper dei metodi Html.CheckBox o Html.CheckBoxFor in quanto non desidero i campi "falsi" nascosti nei miei elenchi di caselle di controllo.

Non esitate a migliorare su questo e ripubblicare :-)

//View 

<%: Html.CheckBoxListFor(model => model.FreightTypeIds, FreightTypeMultiSelectList) %> 

//Controller 

    public ActionResult SomeAction(int[] FreightTypeIds) 
    { 
     //... 

     return View(); 
    } 


//Extension 
public static MvcHtmlString CheckBoxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, IEnumerable<TProperty>>> expression, MultiSelectList allOptions, object htmlAttributes = null) 
{ 
    ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression<TModel, IEnumerable<TProperty>>(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<TProperty> list = expression.Compile().Invoke(htmlHelper.ViewData.Model); 

    // Convert selected value list to a List<string> for easy manipulation 
    IList<string> selectedValues = new List<string>(); 

    if (list != null) 
    { 
     selectedValues = new List<TProperty>(list).ConvertAll<string>(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(
              "<div><input type=\"checkbox\" name=\"{0}\" id=\"{1}_{2}\" " + 
              "value=\"{2}\" {3} /><label for=\"{1}_{2}\">{4}</label></div>", 
              propertyName, 
              TagBuilder.CreateSanitizedId(propertyName), 
              item.Value, 
              selectedValues.Contains(item.Value) ? "checked=\"checked\"" : string.Empty, 
              item.Text); 
    } 

    return MvcHtmlString.Create(divTag.ToString()); 
} 
+0

grazie, questo sembra essere quello che stavo cercando. Proverò una volta a casa. – Venemo

+1

Con alcune modifiche, sono riuscito a farlo funzionare come volevo. Grazie mille per il codice! :) – Venemo

+0

Mi piace! Mi sto solo chiedendo come implementare la validazione (discreto) ora ... –

0

Potresti essere interessato a CheckBoxList Helper for MVC articolo di Jeremiah Clark (purtroppo è datato Nov 2008 e riguarda MVC 1).

+0

L'articolo è buono, ma non è scritto con HTML fortemente tipizzato aiutanti in mente. – Venemo

1

Mentre i dipendenti Microsoft sono probabilmente gli unici che possono rispondere perché tale metodo di supporto non esiste si potrebbe provare:

Modello:

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

Controller:

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

View :

<% using (Html.BeginForm()) { %> 
    <%: Html.EditorFor(x => x.Values) %> 
    <input type="submit" value="OK" /> 
<% } %> 

Come potete vedere, EditorFor gestirà tutto ciò che è necessario.

+0

Questa è una buona idea, ma come ho detto, mi piacerebbe avere qualcosa di simile al comportamento di 'ListBoxFor'. – Venemo

+0

Puoi essere un po 'più specifico? 'ListBoxFor' genera'