Какое событие CheckedListBox запускается после проверки элемента?

У меня есть CheckedListBox, где я хочу событие после проверки элемента, чтобы я мог использовать CheckedItems в новом состоянии.

Так как ItemChecked запускается до обновления CheckedItems, он не будет работать из коробки.

Какой метод или событие можно использовать для уведомления при обновлении CheckedItems?

Ответ 1

Вы можете использовать событие ItemCheck, если вы также проверите новое состояние элемента, по которому щелкают. Это доступно в аргументах события, как e.NewValue. Если установлен флажок NewValue текущий элемент вместе с собственно коллекцией в свою логику:

    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());
        else
            checkedItems.Remove(checkedListBox1.Items[e.Index].ToString());

        foreach (string item in checkedItems)
        {
            ...
        }
    }

В качестве другого примера, чтобы определить, будет ли коллекция пустой после того, как этот элемент (un-) проверен:

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 just one item checked, and it being unchecked at this moment
        ...
    else
        // The collection will not be empty once this click is handled
        ...
}

Ответ 2

Есть много связанных сообщений StackOverflow на этом... Как и решение Бранимира, вот еще два простых:

Отложенное выполнение в ItemCheck (также здесь):

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

Использование события MouseUp:

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

Я предпочитаю первый вариант, так как второй приведет к ложным срабатываниям (т.е. слишком часто срабатыванию).

Ответ 3

Я пробовал это, и он работал:

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

Ответ 4

Вывести из CheckedListBox и реализовать

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

Ответ 5

Хотя это и не идеально, вы можете вычислить CheckedItems, используя аргументы, переданные в событие ItemCheck. Если вы посмотрите на этот пример в MSDN, вы можете решить, был ли новый или измененный элемент проверен или снят, что оставляет вас в подходящем положение для работы с элементами.

Вы даже можете создать новое событие, которое срабатывает после проверки элемента, что даст вам именно то, что вы хотели, если хотите.

Ответ 6

После некоторых тестов я увидел, что событие SelectedIndexChanged запускается после события ItemCheck. Хранить свойство CheckOnClick True

Лучшее кодирование

Ответ 7

Это работает, но не уверен, насколько это элегантно!

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

Ответ 8

Не знаю, применимо ли это, но я хотел использовать контрольный список для фильтрации результатов. Так как пользователь проверял и непроверял элементы, я хотел, чтобы список отображал\скрывать элементы.

У меня были некоторые проблемы, которые привели меня к этому сообщению. Просто хотел поделиться тем, как я это сделал без особого внимания.

Примечание. У меня CheckOnClick = true, но он, вероятно, будет работать без

Событие, которое я использую, это " SelectedIndexChanged"

перечисление, которое я использую, это ".CheckedItems"

Это дает результаты, которые, я думаю, мы можем ожидать. Так упрощено это сводится к....

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

}

Ответ 9

Предполагая, что вы хотите сохранить аргументы из ItemCheck но получите уведомление после изменения модели, она должна выглядеть следующим образом:

CheckedListBox ctrl = new CheckedListBox();
ctrl.ItemCheck += (s, e) => BeginInvoke((MethodInvoker)(() => CheckedItemsChanged(s, e)));

Где CheckedItemsChanged может быть:

private void CheckedItemsChanged(object sender, EventArgs e)
{
    DoYourThing();
}

Ответ 10

Я использую таймер для решения этой проблемы. Включите таймер с помощью события 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

Ответ 11

При обычном поведении, когда мы проверяем один элемент, состояние проверки элемента изменится до того, как обработчик события будет вызван. Но CheckListBox имеет другое поведение: обработчик событий вызывается до изменения состояния проверки элемента, что затрудняет исправление наших заданий.

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

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

Ответ 12

Установите для свойства checkCheckbox CheckOnClick значение true и попробуйте использовать событие MouseUp.