Question CheckedListBox's ItemCheck event : bad timing...

Stonkie

Well-known member
Joined
Sep 12, 2007
Messages
279
Programming Experience
1-3
I need to produce a list of checked entries from a CheckedListBox whenever an item changes, but that ItemCheck event gets thrown before the item's status is actually changed so the checked items list is incorrect.

I found a forum post telling to use the SelectedIndexChanged event instead, but that won't work if the user checks the item using the space bar.

My two alternatives are to :

1. Use the ItemCheckEventArgs to figure out what item changed and how. Since the code that gets the list of checked items is a few methods down on the calls hierachy, I would need to pass the event args around (or more likely an homemade representation of its data for consistency).

2. Use a class member boolean to see if I'm in the ItemCheck event handler and set the item's checked state to its correct value before calling the method that does the processing. The boolean is used to avoid an infinite call of the event handler, it would just return without any processing in the case the event handler is in the call stack itself.

Anyone knows how to write this in a cleaner fashion?

Btw, I also tought about inheriting the CheckedListBox control to override the SetCheckedState method, but it is not virtual...
 
Last edited:
The easiest is to get the current selection collection and if NewValue of ItemCheck event is Checked also add this item to the collection, else remove it.
 
Yeah, that's option 1, but the list is created a few method calls further, so I do not have access to the ItemCheckEventArgs directly unless I send the NewValue and changed index through 2 method calls to the point where it is needed... That totally breaks the meaning of the methods...

Here's the solution I've come up with (option 2). It's a bit of a hack but I think it works well!

VB.NET:
private checkingCategory as Boolean = false

private sub chklistCategories_ItemCheck(sender as Object, e as ItemCheckEventArgs) handles chklistCategories.ItemCheck
    if (!checkingCategory) then
        checkingCategory = true

        chklistCategories.SetItemCheckState(e.Index, e.NewValue)
        ApplyCategoryChanges()
        
        checkingCategory = false
    end if
end sub

I'd be very interested in some cleaner solution in case I need to do this again though!

Thanks for the input JohnH! :)

PS. I translated this from C# pretty fast, the concept is there but the syntax may be broken...
 
You might have more success if you use a datagridview with a checkbox column and a textbox column
 
Yeah, I can customize the DataGridView's appearance to look pretty much the same and I can finally use the DataSource property! :)

Thanks!
 
Just having to do the same as Stonkie, so I'm trying to change a CheckedListBox over to a DataGridView.

1. I've changed the CellBorderStyle to None, but my rows are still too large. I know I can change the row height, but why does the default row height of a DGV differ from the row height of a CLB given the same font?

2. Whilst designing the changeover, I had a CLB and DGV on the same form, both bound to the same datatable. When I select a row on the DGV, .NET automatically selects the corresponding item in the CLB. I've never seen this before - is it a *standard* feature for all .NET controls that are bound to a datasource?
 
1. I've changed the CellBorderStyle to None, but my rows are still too large. I know I can change the row height, but why does the default row height of a DGV differ from the row height of a CLB given the same font?
Padding, or margins

2. Whilst designing the changeover, I had a CLB and DGV on the same form, both bound to the same datatable. When I select a row on the DGV, .NET automatically selects the corresponding item in the CLB. I've never seen this before - is it a *standard* feature for all .NET controls that are bound to a datasource?
It's a standard notion in the concept of MVC. The dataview or bindingsource maintains knowledge of position within a data model. When one controlling element changes that position, all other bound controls naturally see the change. If youre struggling with the concept, consider a webcam looking at some flowers. Hundreds of people view the cam and they see flowers. Then someone moves the cam to show a bowl of fruit. Now all people viewing the camera see fruit.
 
The concept's fine :) What I was struggling with was unexpected SelectedIndexChanged events on a control that didnt have the focus. I'll be more careful in future :D
 
I don't know if this is yet relevant (at least for me it was) but I believe that you can predict if the item is or not being checked (and act according to this supposition) via the ItemCheck event. For instance:

VB.NET:
Private Sub chklist_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles chklist.ItemCheck[INDENT] 
if Not chklist.CheckedItems.Contains(chklist.SelectedItem) then[INDENT] 'Proceed as with the item is being checked
...
[/INDENT]
else[INDENT]
'Proceed otherwise
...
[/INDENT]
end if
[/INDENT]
 
end sub

Sergio
 
Last edited:
My approach:

VB.NET:
    Private Sub CheckedListBox1_ItemCheck(sender As Object, e As System.Windows.Forms.ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
        Dim cList As New List(Of String)
        For Each item In CheckedListBox1.CheckedItems
            cList.Add(item)
        Next

        If Not cList.Contains(CheckedListBox1.Items(e.Index)) Then
            cList.Add(CheckedListBox1.Items(e.Index))
        ElseIf e.NewValue = CheckState.Unchecked Then
            cList.Remove(CheckedListBox1.Items(e.Index))
        End If

        Dim sb As New System.Text.StringBuilder
        For Each i As String In cList
            sb.Append(i)
            sb.Append(" ")
        Next
        MessageBox.Show(sb.ToString(), "Checked Items")


    End Sub

Gino.
 
Last edited:
To get a simple count of the number of checked Items, this is how I approached it through the OnItemCheck event:

Dim checkedCount As Integer
If ice.NewValue = CheckState.Checked Then
checkedCount = Me.CheckedItems.Count + 1
Else
checkedCount = Me.CheckedItems.Count - 1
End If
 
Back
Top