web-dev-qa-db-fra.com

Quel événement CheckedListBox se déclenche après la vérification d'un élément?

J'ai un CheckedListBox où je veux un événement après un élément est vérifié afin que je puisse utiliser CheckedItems avec le nouvel état.

Etant donné que ItemChecked est déclenché avant la mise à jour de CheckedItems, cela ne fonctionnera pas immédiatement.

Quel type de méthode ou d'événement puis-je utiliser pour être averti lorsque les CheckedItems sont mis à jour?

78
hultqvist

Vous pouvez utiliser l'événement ItemCheck si vous vérifiez également le nouvel état de l'élément sur lequel vous cliquez. Ceci est disponible dans les arguments de l'événement, sous la forme e.NewValue. Si NewValue est coché, incluez l'élément actuel avec la collection proprement dite dans votre logique:

    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)
        {
            ...
        }
    }

Autre exemple, pour déterminer si la collection sera vide après que cet élément soit (dés) vérifié:

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
        ...
}
70
Branimir

Il y a beaucoup de publications StackOverflow sur ce sujet ... En plus de Branimir's solution, voici deux autres plus simples:

Exécution différée sur ItemCheck (aussi ici ):

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

Utilisation de l'événement MouseUp :

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

Je préfère la première option, car la deuxième entraînerait des faux positifs (c’est-à-dire qu’elle se déclencherait trop souvent).

27
Dunc

Je l'ai essayé et ça marche:

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

Dérivez de CheckedListBox et implémentez

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

Bien que cela ne soit pas idéal, vous pouvez calculer les CheckedItems en utilisant les arguments transmis à l'événement ItemCheck. Si vous consultez cet exemple sur MSDN , vous pouvez déterminer si le nouvel élément modifié a été coché ou non, ce qui vous laisse dans une position appropriée pour utiliser les éléments.

Vous pouvez même créer un nouvel événement qui se déclenche après la vérification d'un élément, ce qui vous donnerait exactement ce que vous vouliez si vous le souhaitiez.

4
w69rdy

Après quelques tests, j'ai pu constater que l'événement SelectedIndexChanged était déclenché après l'événement ItemCheck. Conservez la propriété CheckOnClick True

Meilleur codage

4
Antonio Leite

Cela fonctionne, pas sûr de son élégance!

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
2
FireMatt

En supposant que vous souhaitiez conserver les arguments de ItemCheck mais que vous soyez averti après la modification du modèle, il devrait ressembler à cela:

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

CheckedItemsChanged pourrait être:

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

Je ne sais pas si cela s'applique, mais je voulais utiliser une liste de contrôle pour filtrer les résultats. Ainsi, en tant qu'utilisateur coché et décoché des éléments, je voulais que la liste affiche\masquer les éléments.

J'avais des problèmes qui m'ont amené à ce poste. Je voulais juste partager comment je l'ai fait sans rien de spécial.

Note: J'ai CheckOnClick = true mais cela fonctionnerait probablement encore sans

L'événement que j'utilise est " SelectedIndexChanged "

l'énumération que j'utilise est " .CheckedItems "

Cela donne les résultats que je pense pouvoir espérer. Si simplifié, cela revient à ...

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

}
1
da_jokker

En comportement normal, lorsque nous vérifions un élément, l'état de contrôle de l'élément change avant que le gestionnaire d'événements ne soit déclenché . Mais un contrôle CheckListBox a un comportement différent: il est difficile de corriger nos emplois.

À mon avis, pour résoudre ce problème, nous devrions différer le gestionnaire d'événements.

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

J'utilise un minuteur pour résoudre ce problème. Activer la minuterie via l'événement ItemCheck. Agissez lors de l'événement Tick du minuteur.

Cela fonctionne que l'élément soit vérifié via un clic de souris ou en appuyant sur la barre d'espacement. Nous tirerons parti du fait que l'élément qui vient d'être coché (ou non coché) est toujours l'élément sélectionné.

L'intervalle du minuteur peut être aussi bas que 1. Au moment où l'événement Tick est déclenché, le nouvel état Checked sera défini.

Ce code VB.NET montre le concept. Vous pouvez utiliser de nombreuses variantes. Vous souhaiterez peut-être augmenter l'intervalle du minuteur pour permettre à l'utilisateur de modifier l'état de la vérification de plusieurs éléments avant de prendre des mesures. Ensuite, dans l'événement Tick, effectuez une passe séquentielle de tous les éléments de la liste ou utilisez sa collection CheckedItems pour prendre les mesures appropriées.

C'est pourquoi nous désactivons d'abord le minuteur dans l'événement ItemCheck. Désactiver, puis Activer provoque le redémarrage de la période d'intervalle.

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
0
Bob Ashcraft