No ItemChecked event in a CheckedListBox?

后端 未结 4 1107
故里飘歌
故里飘歌 2020-11-29 08:53

The ListView control has an ItemCheck event which is fired before the item changes, and an ItemChecked event that is fired aft

相关标签:
4条回答
  • 2020-11-29 09:33

    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.

    0 讨论(0)
  • 2020-11-29 09:41

    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
    
    0 讨论(0)
  • 2020-11-29 09:54
        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;
        }
    
    0 讨论(0)
  • 2020-11-29 09:57

    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
    
    0 讨论(0)
提交回复
热议问题