Событие, зарегистрированное в 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