Нет события ItemChecked в CheckedListBox?
Элемент управления ListView имеет событие ItemCheck, которое вызывается до изменения элемента, и событие ItemChecked, которое вызывается после изменения элемента. Посмотрите этот ТАК вопрос для более подробной информации.
Элемент управления CheckedListBox имеет только событие ItemCheck.
Каков наилучший способ сделать что-то подобное с CheckedListBox?
private void checkedListBox_ItemChecked(object sender ItemCheckedEventArgs e)
{
okButton.Enabled = (checkedListBox.CheckedItems.Count > 0);
}
Дополнительный вопрос: почему нет события CheckedListBox.ItemChecked?
4 ответа
Хорошая уловка для обработки событий, которые вы не можете обработать, когда они возникают, - это задержать обработку. Что вы можете сделать с помощью метода Control.BeginInvoke(), он запускается, как только отправляются все события, побочные эффекты завершаются, и поток пользовательского интерфейса снова начинает простаивать. Часто полезно для TreeView, а также еще один капризный элемент управления.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) {
this.BeginInvoke((MethodInvoker)delegate {
okButton.Enabled = checkedListBox1.CheckedItems.Count > 0;
});
}
На всякий случай: это никак не связано с многопоточностью, а хитрость довольно дешевая.
Почему нет события ItemChecked? Не совсем уверен. CheckedListBox просто не очень хороший элемент управления. Определенно не сделано одним из гуру в оригинальной команде Winforms.
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;
}
Основываясь на ответе Ханса Пассанта, я добавляю общую версию 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
Я использую таймер для решения этой проблемы. Включить таймер через событие ItemCheck. Примите меры в событии Timer Tick.
Это работает независимо от того, проверяется ли элемент щелчком мыши или нажатием пробела. Мы воспользуемся тем, что только что отмеченный (или не отмеченный) элемент всегда является выбранным элементом.
Интервал таймера может составлять всего 1. К тому времени, когда событие Tick будет вызвано, будет установлен новый статус Checked.
Этот код VB.NET демонстрирует концепцию. Есть много вариантов, которые вы можете использовать. Вы можете увеличить интервал таймера, чтобы пользователь мог изменить статус проверки нескольких элементов, прежде чем предпринимать какие-либо действия. Затем в событии Tick сделайте последовательный проход всех
Элементы в списке или используйте его коллекцию CheckedItems для принятия соответствующих мер.
Вот почему мы сначала отключаем Timer в событии ItemCheck. Disable затем Enable заставляет период интервала перезапускаться.
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