Какие триггеры событий CheckedListBox после проверки элемента?


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

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

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

11 73

11 ответов:

можно использовать ItemCheck событие, если вы также проверите новое состояние элемента, который был выбран. Это доступно в случае args, как 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's just one item checked, and it's being unchecked at this moment
        ...
    else
        // The collection will not be empty once this click is handled
        ...
}

есть много связанных сообщений 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);
    }

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

я попробовал это, и это сработало:

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

выводим из 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);
}

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

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

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

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

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

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

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

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

Примечание: у меня 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
        }
   }

}

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

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

здесь CheckedItemsChanged можно:

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

в нормальном поведении, когда мы проверяем один элемент, состояние проверки элемента изменится до того, как обработчик событий поднимется. Но 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());}

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

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

интервал таймера может быть всего 1. К моменту возникновения события Tick будет установлен новый статус Checked.

Это 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