The ListView control has an ItemCheck event which is fired before the item changes, and an ItemChecked event that is fired after the item changes. See this SO question for more detail.
The CheckedListBox control only has the ItemCheck event.
What is the best way to do something like this with a CheckedListBox?
private void checkedListBox_ItemChecked(object sender ItemCheckedEventArgs e)
{
okButton.Enabled = (checkedListBox.CheckedItems.Count > 0);
}
Supplemental question: Why is there no CheckedListBox.ItemChecked event?
Whenever a user clicks a Windows Forms CheckBox control, the Click event occurs.
A nice trick to deal with events that you cannot process when they are raised is to delay the processing. Which you can do with the Control.BeginInvoke() method, it runs as soon as all events are dispatched, side-effects are complete and the UI thread goes idle again. Often helpful for TreeView as well, another cranky control.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) { this.BeginInvoke((MethodInvoker)delegate { okButton.Enabled = checkedListBox1.CheckedItems.Count > 0; }); }
Just in case: this has nothing to do with threading and the trick is quite cheap.
Why no ItemChecked event? Not really sure. CheckedListBox just isn't a very good control. Definitely not done by one of the gurus in the original Winforms team.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) { int count = this.checkedListBox1.CheckedItems.Count; if (e.CurrentValue != CheckState.Checked && e.NewValue == CheckState.Checked) { count += 1; } else if (e.CurrentValue == CheckState.Checked && e.NewValue != CheckState.Checked) { count -= 1; } this.okButton.Enabled = count > 0; }
Based on Hans Passant's answer I am adding a generic VB.NET version. I needed one method which would be called for all CheckedListBox controls on the form. You can easily tweak this if you need separate methods for each control (adds some redundancy though).
Public Class Form1
Delegate Sub ProcessItemCheck(ByRef ListBoxObject As CheckedListBox)
Private Sub ProcessItemCheckSub(ByRef ListBoxObject As CheckedListBox)
' Do your actual ItemCheck stuff here
End Sub
Private Sub CheckedListBox1_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles CheckedListBox1.ItemCheck
Dim Objects As Object() = {CheckedListBox1}
BeginInvoke(New ProcessItemCheck(AddressOf ProcessItemCheckSub), Objects)
End Sub
End Class
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With