2010-12-15 99 views
25

Le contrôle ListView a un événement ItemCheck qui est tiré avant les changements de poste, et un ItemChecked événement qui est tiré après les changements de poste. Voir this SO question pour plus de détails.Aucun événement ItemChecked dans CheckedListBox?

Le contrôle CheckedListBox a uniquement l'événement ItemCheck.

Quelle est la meilleure façon de faire quelque chose comme ça avec un CheckedListBox?

private void checkedListBox_ItemChecked(object sender ItemCheckedEventArgs e) 
{ 
    okButton.Enabled = (checkedListBox.CheckedItems.Count > 0); 
} 

question supplémentaire: Pourquoi est-il aucun cas CheckedListBox.ItemChecked?

+1

double possible de [Quel événement CheckedListBox déclenche après un élément est vérifié] (http://stackoverflow.com/questions/3666682/which-checkedlistbox-event-triggers-after-a-item-is- cochée) – taocp

Répondre

47

Une bonne astuce pour traiter les événements que vous ne pouvez pas traiter lorsqu'ils sont déclenchés est de retarder le traitement. Ce que vous pouvez faire avec la méthode Control.BeginInvoke(), il s'exécute dès que tous les événements sont expédiés, les effets secondaires sont terminés et le thread de l'interface utilisateur redevient inactif. Souvent utile pour TreeView aussi, un autre contrôle grincheux. Juste au cas où: cela n'a rien à voir avec le filetage et le tour est assez bon marché.

Pourquoi aucun événement ItemChecked? Pas vraiment sûr. CheckedListBox n'est tout simplement pas un très bon contrôle. Certainement pas fait par l'un des gourous de l'équipe Winforms originale.

+0

Hehe, je te nervais. Le code intelligent n'est pas vraiment une bonne chose, précisément pour la raison que vous avez donnée. Le code élégant est. –

+3

Un petit hic. "BeginInvoke ne peut pas être appelé sur un contrôle tant que le handle de fenêtre n'a pas été créé", et je définissais l'état via checkedListBox1.SetItemChecked() avant d'afficher le formulaire, ce qui déclenche une exception. –

+1

Rats, vous avez trouvé une échappatoire. Testez this.IsHandleCreated ou déplacez le code vers l'événement Load ou n'inscrivez pas l'événement avant d'avoir initialisé les éléments. Je préférerais l'événement Load (OnLoad, en fait). –

4
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; 
    } 
0

J'utilise une minuterie pour résoudre ce problème. Activez le minuteur via l'événement ItemCheck. Prenez des mesures dans l'événement Timer's Tick.

Cela fonctionne si l'élément est vérifié par un clic de souris ou en appuyant sur la barre d'espace. 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 temporisateur peut être aussi bas que 1. Au moment où l'événement Tick est déclenché, le nouvel état Vérifié sera défini.

Ce code VB.NET montre le concept. Il existe de nombreuses variantes que vous pouvez utiliser. Vous pouvez augmenter l'intervalle du temporisateur pour permettre à l'utilisateur de modifier l'état de contrôle sur plusieurs éléments avant de passer à l'action. Ensuite, dans l'événement Tick, effectuez une passe séquentielle de tous les éléments

é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 temporisateur 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

Basé sur Hans Passant's answer J'ajoute une version générique VB.NET. J'avais besoin d'une méthode qui serait appelée pour tous les contrôles CheckedListBox sur le formulaire. Vous pouvez facilement modifier ceci si vous avez besoin de méthodes séparées pour chaque contrôle (ajoute cependant de la redondance).

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