Tonight I spent sometime playing with checkboxes! (Yes I know, I should get out more…) Here’s what I learned. Let’s say you’ve got a form with a group of checkboxes. That might look something like this:

Yes I know this is one of the most impressive forms you’ve ever seen. But let’s say that you’ve got a group of checkboxes and you need to capture which checkboxes are selected. You could wire up an event handler for the “Save” button’s click event, then write up a bunch of if-else statements to see which checkboxes are checked and yada yada…

Your code might look something like…

if ( checkBox1.Checked ) {}
  if ( checkBox2.Checked ) {}
  if ( checkBox3.Checked ) {}

I didn’t like this so I wanted to come up with a different way, something that’s not so smelly. Here’s what I came up with. The ICheckBoxGroup where T is a full blown type that represents something in the real world.

internal interface ICheckBoxGroup< T > {
      void Add( CheckBox checkbox, T item );
      IEnumerable< T > GetAllEnabled( );
      IEnumerable< T > GetAllThatSatisfies( Predicate< CheckBox > condition );
  }

This allows me to bind a full blown domain object to each checkbox. In this example I’m binding a Sport to each checkbox.

ICheckBoxGroup< ISport > group = new CheckBoxGroup< ISport >( );
  group.Add( checkBox1, Sport.Hockey );
  group.Add( checkBox2, Sport.BasketBall );
  group.Add( checkBox3, Sport.FootBall );
  group.Add( checkBox4, Sport.Golf );
  group.Add( checkBox5, Sport.Tennis );

When the “Save” button is clicked I’m asking for all the Sports that have been selected like this…

StringBuilder builder = new StringBuilder( );
  foreach ( ISport employee in group.GetAllEnabled( ) ) {
      builder.AppendFormat( "{0}{1}", employee, Environment.NewLine );
  }
  MessageBox.Show( builder.ToString( ) );

The “GetAllEnabled” method is returning an IEnumerable. This means there's no conversion from if checkbox1.checked == true then Hockey was selected. You're just handed back the type that the checkbox represents, no translation required. The implementation of CheckBoxGroup looks like this:

public class CheckBoxGroup< T > : ICheckBoxGroup< T > {
      public CheckBoxGroup( ) {
          _checkboxes = new List< CheckBox >( );
      }

      public void Add( CheckBox checkbox, T item ) {
          checkbox.Tag = item;
          checkbox.Text = item.ToString( );
          _checkboxes.Add( checkbox );
      }

      public IEnumerable< T > GetAllEnabled( ) {
          return GetAllThatSatisfies( delegate( CheckBox box ) { return box.Checked; } );
      }

      public IEnumerable< T > GetAllThatSatisfies( Predicate< CheckBox > condition ) {
          foreach ( CheckBox checkBox in _checkboxes ) {
              if ( condition( checkBox ) ) {
                  yield return ( T )checkBox.Tag;
              }
          }
      }

      private readonly IList< CheckBox > _checkboxes;
  }

Just remember to override ToString on your types otherwise the default implementation will just write the fully qualified name of your type as the text next to your checkbox. I know this example could be greatly improved, but after a bus ride home pondering about this, this was what I could come up. Feel free to toss me your example.

PlayingWithCheckboxes.txt (2.4 KB)

comments powered by Disqus