Pages Menu
TwitterRssFacebook

Posted by on Jun 3, 2010 in Development

CheckedListBox Woes

Recently, I had a problem to solve involving displaying lists of checkable items. I found out, the hard way, the limitations of the CheckedListBox and why you may not want to try using it. My woeful tale ended with me using a third-party control to achieve what I was looking for.

The problem

Using a Windows Forms Application, I needed a scrollable list of checkbox items. The number of items and what they were are dynamic, and come from a DataTable. The checkboxes needed to be Indetermindate when they are loaded – that is, neither checked or unchecked but that mysterious third state (in Windows the checkbox is filled in, usually in grey or green). I then needed to know, on an event such as a button click, which of the checkboxes had been ticked, and which had been unticked (ignoring any left in the third state).

First Solution

Initially I used a CheckedListBox. This is in the standard Toolbox, and offers “a ListBox in which a check box is displayed to the left of each item.” Sounds perfect, especially when I found out that the check boxes supported the indeterminate state.

The first hurdle was this interesting find: Note   You cannot bind data to a CheckedListBox. Use a ComboBox or a ListBox for this instead. This took a moment to digest. This is a top-level, Microsoft-provided Toolbox control living in the System.Windows.Form namespace, described as a type of ListBox, but you can’t data bind to it? That seems like madness.

I should have walked away at this point. However, I’d already sunk an hour into this, so I write a For..Next to populate the CheckedListBox. That worked OK:

This gave me exactly what I was looking for. However, this is when I ran into my second problem: you can’t enumerate the CheckedListBox and get CheckBoxes back. If you go through the .Items property you get a String with the title of the CheckBox. Strings! Pretty, but not helpful.

CheckedListBox does have both a .CheckedIndices and a .CheckedItems property. If anyone can tell me what the difference between these is, I’d be very grateful. Initially I didn’t think this would be helpful – I thought it would only show items in the checked state. It turns out that apparently indeterminate items are also shown, along with their CheckState. So, I probably could have used this, although it would be a fairly nasty hack of finding out what had been specifically un-checked using a process of elimination.

Second Solution

At the point I decided to leave the CheckedListBox well alone, and use something else. I was also getting fed-up, so I didn’t spend very long on the following solutions. I used a ListView, set it’s CheckBoxes property to True and added Items, but then found that those CheckBoxes couldn’t be indeterminate. I then switched to a ListBox and added CheckBox controls to its Control collection. I didn’t spend very long on this, but I ran into a problem where only the first control would ever be displayed. I may look into this another time, unless anyone else can shed light on it?

Final Solution

By now I was feeling pretty annoyed, and my Google searches were getting wider and wider. I picked up a third-party control from CodeProject, called Glacial ListView Control. It’s written in C# and is arguably complete overkill for what I need, but I’m glad I found it. (I’m now re-thinking some early DataGridViews I did and wondering if I could refactor them to use this).

Using the Glacial ListView Control I could add a CheckBox as a control quite easily:

For Each drRow As DataRow In SourceData.Rows
chkBox = New CheckBox
chkBox.Text = drRow(SourceDataDescColumn).ToString
chkBox.CheckState = Windows.Forms.CheckState.Indeterminate

Dim GLItem As GlacialComponents.Controls.GLItem = MultiSelectBox.Items.Add(drRow(0).ToString)
GLItem.SubItems(0).Control = chkBox
Next

The CheckBox renders exactly as you might expect it to. Even better, it’s a doddle to work out afterwards what’s been clicked and what hasn’t:

For Each GLRowItem As GLItem In chkBox.Items
chkCheckBox = CType(GLRowItem.SubItems(0).Control, CheckBox)

If chkCheckBox.CheckState = Windows.Forms.CheckState.Checked Then
SelectedItems.Add(CInt(GLRowItem.Text))
ElseIf chkCheckBox.CheckState = Windows.Forms.CheckState.Unchecked Then
UnSelectedItems.Add(CInt(GLRowItem.Text))
End If
Next

There’s many other things that the Glacial ListView Control can do, such as the pretty alternative row colourings, multiple control embedding and other such stuff. I’m glad I’ve found it, and I’m sure I’ll be using it again in the future.

Written by Tom Morgan

Tom is a Microsoft Teams Platform developer and Microsoft MVP who has been blogging for over a decade. Find out more.
Buy the book: Building and Developing Apps & Bots for Microsoft Teams. Now available to purchase online with free updates.

Post a Reply

Your email address will not be published. Required fields are marked *

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