Which CheckedListBox event triggers after a item is checked?
You can use the ItemCheck
event, if you also check the new state of the item which is being clicked. This is available in the event args, as e.NewValue
. If NewValue
is checked, include the current item along with the collection proper in your logic:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
List<string> checkedItems = new List<string>();
foreach (var item in checkedListBox1.CheckedItems)
checkedItems.Add(item.ToString());
if (e.NewValue == CheckState.Checked)
checkedItems.Add(checkedListBox1.Items[e.Index].ToString());
else
checkedItems.Remove(checkedListBox1.Items[e.Index].ToString());
foreach (string item in checkedItems)
{
...
}
}
As another example, to determine if the collection will be empty after this item is (un-)checked:
private void ListProjects_ItemCheck(object sender, ItemCheckEventArgs args)
{
if (ListProjects.CheckedItems.Count == 1 && args.NewValue == CheckState.Unchecked)
// The collection is about to be emptied: there's just one item checked, and it's being unchecked at this moment
...
else
// The collection will not be empty once this click is handled
...
}
No ItemChecked event in a CheckedListBox?
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.
Manage CheckedListBox ItemCheck event to run after an item checked not before
CheckedListBox.ItemCheck Event
The check state is not updated until after the ItemCheck event occurs.
To run some codes after the item checked, you should use a workaround.
Best Option
You can use this option (Thanks to Hans Passant for this post):
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
this.BeginInvoke(new Action(() =>
{
//Do the after check tasks here
}));
}
Another option
If in middle of ItemCheck Event, you need to know state of item, you should use
e.NewValue
instead of usingcheckedListBox1.GetItemChecked(i)
If you need to pass a list of checked indices to a method do this:
Using the code:
var checkedIndices = this.checkedListBox1.CheckedIndices.Cast<int>().ToList();
if (e.NewValue == CheckState.Checked)
checkedIndices.Add(e.Index);
else
if(checkedIndices.Contains(e.Index))
checkedIndices.Remove(e.Index);
//now you can do what you need to checkedIndices
//Here if after check but you should use the local variable checkedIndices
//to find checked indices
Another Option
In middle of ItemCheck event, remove handler of ItemCheck, SetItemCheckState and then add handler egain.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
var control = (CheckedListBox)sender;
// Remove handler
control.ItemCheck -= checkedListBox_ItemCheck;
control.SetItemCheckState(e.Index, e.NewValue);
// Add handler again
control.ItemCheck += checkedListBox_ItemCheck;
//Here is After Check, do additional stuff here
}
CheckedListBox event *after* CheckState changed
You don't need another event, just handle the ItemChecked
and use the e.NewValue
to get the count of the checked items after the CheckState
is changed and not when the ItemChecked
event is raised.
private void NumbersListItemChecked(object sender, ItemCheckEventArgs e)
{
var s = sender as CheckedListBox;
var count = s.CheckedIndices.Count + (e.NewValue == CheckState.Checked ? 1 : -1);
if (count > 5)
e.NewValue = CheckState.Unchecked;
ModifyButton.Enabled = count >= 5;
}
CheckedListBox ItemCheck event only fires on fast double click?
The problem is that the SelectedIndexChanged event gets fired directly after the ItemCheck event. That means it gets fired before every ItemCheck and then immediately after. The label will not show the change as it happens too fast, but switching to MessageBox.Show() verifies that it is getting fired directly after.
C# CheckedListBox.ItemCheck Event
You need to add this handler to your CheckBoxList.ItemCheck
event(in form constructor after InitializeComponents()
or in Load
handler):
checkedListBox1.ItemCheck += checkedListBox1_ItemCheck;
Clear CheckedListBox after ItemCheck Event
Change your code to run the logic after the check state of the item updated:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
checkedListBox1.BeginInvoke(new Action(() =>
{
if (checkedListBox1.CheckedItems.Count == checkedListBox1.Items.Count)
{
checkedListBox1.Items.Clear();
}
}));
}
According to the documentations, by default, when the ItemCheck
event raises, the check state of the item is not updated until after the ItemCheck
event occurs. It means it tries to update the check state of the item after running the code that you have in the event handler. As a result in your code, it tries to update item check state after the item removed from items collection and that's why an exception happens. You can see what happens in stack trace, also in source code of the control.
In above code, using BeginInvoke
we delay running the code after the check state is updated. You can read more about it in this post.
Get index and name of checked item in checkedListbox
If you check out the Remarks on CheckedListBox.ItemChecked
it states
The check state is not updated until after the ItemCheck event occurs.
When you check the first item in your CheckedListBox
, your event triggers but the check state of the item has not updated yet. So, there are no items in checkedListBox1.CheckedItems
and so there isn't a message box displayed.
When you check a second item, the only item in checkedListBox1.CheckedItems
is the one you previously checked. So, that is the one that displays.
I'm assuming from the question that you just want to show the item whose check state is being modified. If so, you can use the ItemCheckEventArgs
to get the information you need.
void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
MessageBox.Show("Item with title \"" + checkedListBox1.Items[e.Index].ToString() +
"\" was checked. The new check state is " + e.NewValue.ToString();
}
Reliable Way To Cancel ItemCheck Event On CheckedListBox
It is easy to do with the ItemCheck event. Just set the value back. Like this:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
if (someCondition) e.NewValue = e.CurrentValue;
else {
// Regular stuff
//...
}
}
Related Topics
Print HTML Document from Windows Service Without Print Dialog
Regular Expression to Get the Src of Images in C#
How to Draw a Rounded Rectangle with Winforms (.Net)
Get All Types Implementing Specific Open Generic Type
Sortable Jqgrid Using Linq to MySQL (Dblinq) and Dynamic Linq - Orderby Doesn't Work
Any Trick to Use Opacity on a Panel in Visual Studio Window Form
Visualizing an Ast Created with Antlr (In a .Net Environment)
How to Make Correct Date Format When Writing Data to Excel
Deserializing JSON Array into Strongly Typed .Net Object
How to Configure Many to Many Relationship Using Entity Framework Fluent API
Applying % Number Format to a Cell Value Using Openxml
How to Find the Position of a Cursor in a Text Box? C#
How to Apply Indenting Serialization Only to Some Properties
C# Httpwebrequest the Underlying Connection Was Closed: an Unexpected Error Occurred on a Send