Three state checkbox in

Yesterday I need to implement in a quick way a three style checkbox in a project based on 3.5. The requirements stated that I must not spend too much time designing an entire new control, but the solution should be usable by other people with minimum impact. Here is the result I obtained.


The checkbox can be, selected, not selected, or not used and when it is not used it is blue, like the one in windows forms. This was needed to satisfy a requirement, I need to make possible for the user to specify complex filters, and I have boolean fields on my entities where the user can ask for: filter only the one with field==true or field==false or no filter for that field. To achieve the result you can simply use a standard checkbox.

   1: <asp:CheckBox ID="chkCCSignaled" CssClass="threestate" runat="server" />

The only stuff you need is that you need to assign the “threestate” style to the checkbox. (this satisfy the need of the minimuym impact, other developers that want to use that checkbox can simply add that css to a standard checkbox). The dirty work is done by an unobtrusive jquery javascript that gets injected with the masterpage.

   1: $(function() {

   2:     $('span.threestate')

   3:         .log('checkboxes')

   4:         .each(function() {

   5:             var thespan = $(this);

   6:             var checkbox = $(thespan.children().get(0));

   7:             var name = checkbox.attr('id') + '_hf';


   9:             var innerhf = $('<input type="hidden" name="' + name + '" id="' + name + '" />');

  10:             thespan.prepend(innerhf);


  12:             var innerslide = $('<div style="width:' + thespan.width() + 'px; height:' + thespan.height() + 'px" class="chboverlay" />')

  13:             .css('opacity', 0.8)

  14:                 .click(function() {

  15:                     //debugger;

  16:                     if (innerhf.val() == 2) {

  17:                         $(this).css('opacity', 0.0)

  18:                         checkbox.attr('checked', true);

  19:                         innerhf.val(1);

  20:                     } else {

  21:                         if (innerhf.val() == 1) {

  22:                             checkbox.attr('checked', false);

  23:                             innerhf.val(0);

  24:                         } else {

  25:                             $(this).css('opacity', 0.8)

  26:                             checkbox.attr('checked', false);

  27:                             innerhf.val(2);

  28:                         }

  29:                     }

  30:                 });

  31:             var chkvalue = "2";


  33:             if (checkbox.parent().attr('threestatevalue') != undefined) {

  34:                 chkvalue = checkbox.parent().attr('threestatevalue');

  35:                 if (chkvalue == "0" || chkvalue == "1") {

  36:                     innerslide.css('opacity', 0.0)

  37:                 }

  38:             }

  39:             innerhf.val(chkvalue);

  40:             thespan.prepend(innerslide);

  41:         });

The solution is quite simple, I create a new div with a specific class to overlay the checkbox and create the blue layer when the checkbox is in state “undefined”. the tricky part is that I need to manage three possible value for the checkbox and I need to pass that value to the server during a postback, so I create dynamically an hidden input with the same id of the checkbox and the “_hf” string at the end. In that hidden field I store the actual value of the checkbox, 0 not selected, 1 selected and 2 undefined. The rest of the script is needed to manage the transition between states reacting to the click event of the checkbox.

In the server code I need to grab the three state value, so I created a simple extension method.

   1: Namespace SiteCode.V2

   2:     Public Module ThreeStateCheckbox


   4:         <Extension()> _

   5:         Public Function GetThreeStateValue(ByVal cb As CheckBox) As Nullable(Of Boolean)

   6:             Dim value As String = HttpContext.Current.Request.Form(cb.ClientID + "_hf")

   7:             cb.Attributes("threestatevalue") = value

   8:             Select Case value

   9:                 Case "0" : Return False

  10:                 Case "1" : Return True

  11:                 Case "2" : Return Nothing

  12:             End Select


  14:         End Function

  15:     End Module

  16: End Namespace

This simple method is an extension method for the checkbox control, it simply grab the value of the dynamically generated hidden field from the Request.Form collection. After taking actual value, he add the attribute “threestatevalue” to the checkbox, because the client script should be able to restore the state of the checkbox after a postback. Now you can simply get the value with this code.

   1: Public ReadOnly Property IsCCChecked() As Nullable(Of Boolean)

   2:     Get

   3:         Return chkCC.GetThreeStateValue()

   4:     End Get

   5: End Property

With this structure the developer can simply add the css (as seen before) and use this extension method to grab the value, this without the need to author a whole new control.

I used this in a user control (that represents a complex filter and gets used in several pages), and this user control exposes the selection status to external control with readonly property that return Nullable(of Boolean). Thanks to extension method I can simply add the css to the checkbox, use GetThreeStateValue to grab the actual status of the checkbox and the game is done.



Published by

Ricci Gian Maria

.Net programmer, User group and community enthusiast, programmer - aspiring architect - and guitar player :). Visual Studio ALM MVP

2 thoughts on “Three state checkbox in”

  1. This appears to be precisely what I need. Unfortunately, I am getting the error “expecting more source characters” when I attempt to include the script on a page. I also get that error from the Visual Studio 2008 developer on the js page where I put the script

    Can you tell me what I am doing wrong.

  2. This is indeed a strange error, it is a server error (code 500) or it is a javascript error? Have you an example that you can send me by email so I give it a check?


Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.