Событие, зарегистрированное в CheckedListBox?

Элемент управления ListView имеет событие ItemCheck, которое запускается до изменения элемента, и событие ItemChecked, которое запускается после изменения элемента. Подробнее см. этот вопрос SO.

Контроллер CheckedListBox имеет событие ItemCheck.

Каков наилучший способ сделать что-то подобное с помощью CheckedListBox?

private void checkedListBox_ItemChecked(object sender ItemCheckedEventArgs e)
{
    okButton.Enabled = (checkedListBox.CheckedItems.Count > 0);
}

Дополнительный вопрос: Почему нет события CheckedListBox.ItemChecked?

Ответ 1

Хороший трюк, чтобы иметь дело с событиями, которые вы не можете обработать, когда они подняты, - это отложить обработку. Что вы можете сделать с помощью метода Control.BeginInvoke(), он запускается, как только все события отправляются, побочные эффекты завершены, а поток пользовательского интерфейса снова простаивает. Часто полезно для TreeView, а также еще один капризный элемент управления.

    private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
        this.BeginInvoke((MethodInvoker)delegate { 
            okButton.Enabled = checkedListBox1.CheckedItems.Count > 0;
        });
    }

На всякий случай: это не имеет ничего общего с потоками, и трюк довольно дешев.

Почему не зарегистрировано событие ItemChecked? Не совсем уверен. CheckedListBox просто не очень хороший контроль. Определенно не сделано одним из гуру в исходной команде Winforms.

Ответ 2

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

Ответ 3

Я использую таймер для решения этой проблемы. Включите таймер с помощью события ItemCheck. Примите меры в событии Timer Tick.

Это работает, проверяется ли элемент с помощью щелчка мыши или нажатием клавиши пробела. Мы воспользуемся тем фактом, что элемент, который только что был проверен (или не проверен), всегда является выбранным элементом.

Интервал таймера может быть таким же низким, как 1. К моменту появления события Tick будет установлен новый статус "Проверено".

Этот код VB.NET показывает концепцию. Есть много вариантов, которые вы можете использовать. Вы можете увеличить интервал таймера, чтобы пользователь мог изменить статус проверки на несколько элементов, прежде чем предпринимать действия. Затем в событии Tick сделайте последовательный проход всех

Элементы в списке или используйте коллекцию CheckedItems для принятия соответствующих мер.

Вот почему мы сначала отключили Таймер в событии ItemCheck. Отключить, затем Включить вызывает повторный запуск периода интервала.

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

Ответ 4

На основе Ответ Hans Passant Я добавляю общую версию VB.NET. Мне нужен был один метод, который будет вызываться для всех элементов CheckedListBox в форме. Вы можете легко настроить его, если вам нужны отдельные методы для каждого элемента управления (добавляет некоторую избыточность).

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