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
...
}
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;
}
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.
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;
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();
}
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.
User checked item in CheckedListBox
Using the ItemCheck
event handler is the correct method for detecting when the user ticks or un-ticks an item in the CheckedListBox
. And yes, it will also fire when the item is checked/unchecked programmitically.
If you don't want the event fired when you set/unset items programmatically, you should remove the event handler before hand.
Assuming your event handler looks like this:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
{
Debug.Print("Checked");
}
else if (e.NewValue == CheckState.Unchecked)
{
Debug.Print("Un-Checked");
}
}
Before you set/unset items programmatically, you should add the line:
this.checkedListBox1.ItemCheck -= this.checkedListBox1_ItemCheck;
and after the items have been set/unset you in code, re-add the event handler with:
this.checkedListBox1.ItemCheck += this.checkedListBox1_ItemCheck;
Windows C# CheckedListBox Checked Item Event Handling
A standard Windows Forms trick is to delay running code until all event side-effects have been completed. You delay running code with the Control.BeginInvoke() method. This will fix your problem:
private void checkedListBox1_SelectedIndexChanged(object sender, EventArgs e) {
this.BeginInvoke(new MethodInvoker(evalList), null);
}
private void evalList() {
bool any = false;
for (int ix = 0; ix < checkedListBox1.Items.Count; ++ix) {
if (checkedListBox1.GetItemChecked(ix)) {
any = true;
break;
}
}
btnInstall.Enabled = any;
}
Related Topics
Sqlexception:String or Binary Data Would Be Truncated
Troubleshooting "Program Does Not Contain a Static 'Main' Method" When It Clearly Does...
How to Convert String "07:35" (Hh:Mm) to Timespan
Regex: Repeated Capturing Groups
Working with Appdomain.Assemblyresolve Event
Parsing HTML to Get Content Using C#
How to Drag a Usercontrol Inside a Canvas
Sorting an Array of Folder Names Like Windows Explorer (Numerically and Alphabetically) - Vb.Net
Itextsharp - How to Get the Position of Word on a Page
Formatting Datetime in ASP.NET Core 3.0 Using System.Text.JSON
No Database Provider Has Been Configured for This Dbcontext' on Signinmanager.Passwordsigninasync
Count Number of Mondays in a Given Date Range