ASP.NET MVC CheckBoxList

This is a very simple implementation of a check box list that we use rather frequently and which hasn’t let us down (yet).

First thing to do is to write a class inheriting from Dictionary<T, bool> for our multiple choice select list, something like the following:

public class CheckedList<T> : Dictionary<T, bool>

The idea is quite simply having a boolean value per each entity we want our users to be able to select. The dictionary also allows us not to worry about duplications…

then we add an HtmlHelper extension method:

public static class HtmlHelperExtensions
 {
 public static string CheckBoxList<T, TModel, TValue, TText>(this HtmlHelper<TModel> helper, string listName, string valueProperty,
 string textProperty, CheckedList<T> checkedList, Func<T, TValue> value, Func<T, TText> text)
 {
 StringBuilder builder = new StringBuilder();
 for (int i = 0; i < checkedList.Count; i++)
 {
 T item = checkedList.Keys.ToList()[i];
 builder.AppendLine("<p>");
 builder.AppendLine(helper.Hidden(listName + "[" + i + "].Key." + valueProperty, value(item)).ToHtmlString());
 builder.AppendLine(helper.Hidden(listName + "[" + i + "].Key." + textProperty, text(item)).ToHtmlString());
 builder.AppendLine(helper.CheckBox(listName + "[" + i + "].Value", checkedList[item]).ToHtmlString());
 builder.AppendLine(text(item).ToString());
 builder.AppendLine("</p>");
 }
 return builder.ToString();
 }
 }

This extension method could be refactored so that it’ll take Expression<Func… , that way we could extract the names of the value and text properties.

What’s left now to do is simply call the extension method from our View like so:

<%= Html.CheckBoxList("MyCheckedList", "Id", "Name", Model.MyCheckedList, x=>x.Id, x=>x.Name) %> 

Needless to say, this is only a demo and serves just to show what a check box list can be achieved; for more features and more possibilities, you could implement your very own IDictionary<T, bool>, that way you could extend and add whatever you need.

noice 🙂

09/03/2010

Seeing that the post seem to get quite a few hits and finds itself on the first page of a google search for the terms ‘mvc checkbox list’, I thought I should provide a sample project on github. Let me know if there are any problems.

Advertisements
Explore posts in the same categories: ASP.NET MVC

Tags:

You can comment below, or link to this permanent URL from your own site.

17 Comments on “ASP.NET MVC CheckBoxList”


  1. Thanks for the information, you’re a time saver!

  2. Carson Herrick Says:

    I got this working quite fast. Your github sample was valuable. Thanks so much.

    • Carson Herrick Says:

      Oh man. I think I spoke too soon.
      I did have it working great. But now… the model parameter is getting passed into my controller post action handler as null. The data in the ValueProvider looks perfect.

      Have you ever experienced this? Any ideas…?

      • Nieve Says:

        Hey,
        check the name attributes on your checkboxes- they’ll have to be MySelectableList[0] and so on…where MySelectableList is the name of your property (if the list is your model, make sure the name attribute corresponds to the name of the parameter passed in your post action).

        Let me know if this helps.

  3. Carson Herrick Says:

    Thanks Nieve,
    Yeah, I left the default “model” for the name attribute and the name of my parameter.

    I’m sure that my problems stem from the fact that I moved the form into a partial view (.ascx) and am trying to post to a different named method.

    Mitigations.ascx
    ——
    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl” %>

    <%CheckedList checkedList = CheckedList.GetList(-1);
    using (Html.BeginForm(“InsertMitigation”, “Design”, new { @model = checkedList }, FormMethod.Post)){%>

    x.MitigationTypeId, x => x.Name)%>

    That form passes an empty dictionary into the model parameter.

    I have also tried
    Html.BeginForm(“InsertMitigation”, “Design”)
    and
    Html.BeginForm(“InsertMitigation”, “Design”, FormMethod.Post, new { @model = checkedList })
    which both cause the model parameter to be null.

    I know I’m missing something fundamental re: how to handle posting from partial views… just not sure what. Any more help would be greatly appreciated.

    • Carson Herrick Says:

      Oops. Code didn’t work. Let me try code tags…


      <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>



      <%
      CheckedList checkedList = CheckedList.GetList(-1);

      using (Html.BeginForm("InsertMitigation", "Design", FormMethod.Post, new { @model = checkedList }))
      {%>



      x.MitigationTypeId, x => x.Name)%>

      • Carson Herrick Says:

        Arg. Code nuggets messing up. So sorry about the spam.


        x.MitigationTypeId, x => x.Name)%>

  4. Nieve Says:

    Right,
    can you just have a look also at the actual html that gets rendered- how do the <input type="checkbox"…
    elements look like? what are their 'name' attributes values?

  5. Carson Herrick Says:

    name=”model[0].Value”
    name=”model[1].Value”

    • Nieve Says:

      OK,
      in that case, do you have hiddens per each key?
      name=”model[0].Key.Id” value=”42″ etc’..?

      • Carson Herrick Says:

        Yes. All the data is fine. Like I said, the model was binding perfectly, before.
        I started playing around with a custom model binder, but again, the DefaultModelBinder works perfectly from a standard .aspx view, so I don’t really think a custom model binder is necessary.

  6. Nieve Says:

    Ohhh!! Now I get you…
    Sorry, haven’t been too attentive, it’s been a long day.

    Yeah, so if you’re really insisting on having a custom model binder, you can do whatever you feel like doing inside, however you’ll have to call base.BindModel inside your overriding of the BindModel method so that the default model binder (which would be the parent of your custom binder) would do all the work for you. Otherwise, you’ll have to deal with the parsing of the name value collection and all that…

  7. Carson Herrick Says:

    Got it!

    I was trying to use a checked list of native entity types for my model. The DefaultModelBinder did not like that, apparently. I created a ViewModel to wrap up my native type, changed my parameter to expect a CheckedList, and I was golden.

    …man, that was a hard, painful lesson. When they say you should always use a ViewModel, they really mean it.

    • Carson Herrick Says:

      …to expect a CheckedList>CustomType<, that is…

      (Not being able to type brackets in this page is really annoying.)

      • Carson Herrick Says:

        Crap, then I go and get my gt’s and lt’s backwards!!! What a day.

      • Nieve Says:

        oh, hang on- your HttpPost action didn’t have a parameter (CheckedList model) ?? If so then yeah, it’d have never worked! You can have a CheckedList of whatever type you want as long as the type has an empty ctor AFAIR.
        BTW- you can have a model with a CheckedList property in it as well, maybe I should add this to the example.

  8. Carson Herrick Says:

    No. It always had a CheckedList model parameter. More specifically, it used to have a (CheckedList<NativeEntityType> model) parameter. I changed it to (CheckedList<ModelViewCustomType> model) and everything started working.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: