Home » c# » Which CheckedListBox event triggers after a item is checked?

Which CheckedListBox event triggers after a item is checked?

Posted by: admin November 29, 2017 Leave a comment

Questions:

I have a CheckedListBox where I want an event after an item is checked so that I can use CheckedItems with the new state.

Since ItemChecked is fired before CheckedItems is updated it won’t work out of the box.

What kind of method or event can I use to be notified when the CheckedItems is updated?

Answers:

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());

        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
        ...
}

Questions:
Answers:

There are lots of related StackOverflow posts on this… As well as Branimir’s solution, here are two more simple ones:

Delayed execution on ItemCheck (also here):

    void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
    {
        this.BeginInvoke((MethodInvoker) (
            () => Console.WriteLine(checkedListBox1.SelectedItems.Count)));
    }

Using the MouseUp event:

    void checkedListBox1_MouseUp(object sender, MouseEventArgs e)
    {
        Console.WriteLine(checkedListBox1.SelectedItems.Count);
    }

I prefer the first option, as the second would result in false positives (i.e. firing too often).

Questions:
Answers:

I tried this and it worked:

private void clbOrg_ItemCheck(object sender, ItemCheckEventArgs e)
{
    CheckedListBox clb = (CheckedListBox)sender;
    // Switch off event handler
    clb.ItemCheck -= clbOrg_ItemCheck;
    clb.SetItemCheckState(e.Index, e.NewValue);
    // Switch on event handler
    clb.ItemCheck += clbOrg_ItemCheck;

    // Now you can go further
    CallExternalRoutine();        
}

Questions:
Answers:

Derive from CheckedListBox and implement

/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.CheckedListBox.ItemCheck"/> event.
/// </summary>
/// <param name="ice">An <see cref="T:System.Windows.Forms.ItemCheckEventArgs"/> that contains the event data.
///                 </param>
protected override void OnItemCheck(ItemCheckEventArgs e)
{           
    base.OnItemCheck(e);

    EventHandler handler = AfterItemCheck;
    if (handler != null)
    {
        Delegate[] invocationList = AfterItemCheck.GetInvocationList();
        foreach (var receiver in invocationList)
        {
            AfterItemCheck -= (EventHandler) receiver;
        }

        SetItemCheckState(e.Index, e.NewValue);

        foreach (var receiver in invocationList)
        {
            AfterItemCheck += (EventHandler) receiver;
        }
    }
    OnAfterItemCheck(EventArgs.Empty);
}

public event EventHandler AfterItemCheck;

public void OnAfterItemCheck(EventArgs e)
{
    EventHandler handler = AfterItemCheck;
    if (handler != null)
        handler(this, e);
}

Questions:
Answers:

Although not ideal, you can calculate the CheckedItems using the arguments that are passed through to the ItemCheck event. If you look at this example on MSDN, you can work out whether the newly changed item has been checked or unchecked, which leaves you in a suitable position to work with the items.

You could even create a new event that fires after an item is checked, which would give you exactly what you wanted if you wished.

Questions:
Answers:

After some tests, I could see that the event SelectedIndexChanged is triggered after the event ItemCheck. Keep the property CheckOnClick True

Best coding

Questions:
Answers:

This works, not sure how elegant it is though!

Private Sub chkFilters_Changed(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkFilters.ItemCheck
    Static Updating As Boolean
    If Updating Then Exit Sub
    Updating = True

    Dim cmbBox As CheckedListBox = sender
    Dim Item As ItemCheckEventArgs = e

    If Item.NewValue = CheckState.Checked Then
        cmbBox.SetItemChecked(Item.Index, True)
    Else
        cmbBox.SetItemChecked(Item.Index, False)
    End If

    'Do something with the updated checked box
    Call LoadListData(Me, False)

    Updating = False
End Sub

Questions:
Answers:

Don’t know if this applies but I wanted to use a checklistbox to filter results. So as the user checked and unchecked items I wanted the list to show\hide items.

I was having some issues which led me to this post. Just wanted to share how I did it without anything special.

Note: I have CheckOnClick = true but it would probably still work without

The event I use is “SelectedIndexChanged

the enumeration I use is “.CheckedItems

This give the results I think we may expect. So simplified it comes down to ….

private void clb1_SelectedIndexChanged(object sender, EventArgs e)
{
   // This just spits out what is selected for testing
   foreach (string strChoice in clb1.CheckedItems)
   {
      listBox1.Items.Add(strChoice);
   }

   //Something more like what I'm actually doing
   foreach (object myRecord in myRecords)
   {
        if (clb1.CheckItems.Contains(myRecord["fieldname"])
        {
            //Display this record
        }
   }

}

Questions:
Answers:

In normal behaviour, when we check one item, item’s check state will change before event handler raise.
But CheckListBox work with different behaviour: Event handler raise before check state of item change and make it difficult to correct our jobs.

In my oppinion, to solve this problem, we should defer event handler.

private void _clb_ItemCheck(object sender, ItemCheckEventArgs e) {
 // Defer event handler execution
 Task.Factory.StartNew(() => {
     Thread.Sleep(1000);
     // Do your job at here
 })
 .ContinueWith(t => {
     // Then update GUI at here
 },TaskScheduler.FromCurrentSynchronizationContext());}

Questions:
Answers:

Set the checkedlistbox’s CheckOnClick property to true and try using MouseUp event.

Questions:
Answers:

I use a Timer to solve this problem. Enable the timer via the ItemCheck event. Take action in the Timer’s Tick event.

This works whether the item is checked via a mouse click or by pressing the Space-Bar. We’ll take advantage of the fact that the item just checked (or un-checked) is always the Selected Item.

The Timer’s Interval can be as low as 1. By the time the Tick event is raised, the new Checked status will be set.

This VB.NET code shows the concept. There are many variations you can employ. You may want to increase the Timer’s Interval to allow the user to change the check status on several items before taking action. Then in the Tick event, make a sequential pass of all the Items in the List or use its CheckedItems collection to take appropriate action.

That’s why we first disable the Timer in the ItemCheck event. Disable then Enable causes the Interval period to re-start.

Private Sub ckl_ItemCheck(ByVal sender As Object, _
                          ByVal e As System.Windows.Forms.ItemCheckEventArgs) _
    Handles ckl.ItemCheck

tmr.Enabled = False
tmr.Enabled = True

End Sub


Private Sub tmr_Tick(ByVal sender As System.Object, _
                     ByVal e As System.EventArgs) _
    Handles tmr.Tick

tmr.Enabled = False
Debug.Write(ckl.SelectedIndex)
Debug.Write(": ")
Debug.WriteLine(ckl.GetItemChecked(ckl.SelectedIndex).ToString)

End Sub