2010-12-15 14 views
25

El control ListView tiene una caso ItemCheck que se dispara antes de el elemento cambiará, y un ItemChecked evento que se dispara después de el elemento cambiará. Ver this SO question para más detalles.No evento ItemChecked en un CheckedListBox?

El control CheckedListBox solo tiene el evento ItemCheck.

¿Cuál es la mejor manera de hacer algo como esto con un CheckedListBox?

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

pregunta adicional: ¿Por qué hay ningún caso CheckedListBox.ItemChecked?

+1

posible duplicado de [¿Qué evento CheckedListBox desencadena después se comprueba un artículo?] (Http://stackoverflow.com/questions/3666682/which-checkedlistbox-event-triggers-after-a-item-is- comprobado) – taocp

Respuesta

47

Un buen truco para tratar los eventos que no se pueden procesar cuando se plantean es retrasar el procesamiento. Lo que puede hacer con el método Control.BeginInvoke(), se ejecuta tan pronto como se envían todos los eventos, se completan los efectos secundarios y el hilo de la interfaz de usuario permanece inactivo nuevamente. A menudo también es útil para TreeView, otro control malhumorado.

private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e) { 
     this.BeginInvoke((MethodInvoker)delegate { 
      okButton.Enabled = checkedListBox1.CheckedItems.Count > 0; 
     }); 
    } 

Por las dudas: esto no tiene nada que ver con el roscado y el truco es bastante barato.

¿Por qué no hay un evento ItemChecked? No muy seguro. CheckedListBox simplemente no es un muy buen control. Definitivamente no lo hizo uno de los gurús en el equipo original de Winforms.

+0

Jeje, te estaba engañando. Por cierto, el código inteligente no es una buena cosa, precisamente por la razón que diste. El código elegante es. –

+3

Una pequeña pega. "No se puede llamar a BeginInvoke en un control hasta que se haya creado el identificador de ventana", y estaba configurando el estado mediante checkListBox1.SetItemChecked() antes de mostrar el formulario, que arroja una excepción. –

+1

Ratas, encontraron una laguna. Pruebe this.IsHandleCreated o mueva el código al evento Load o no se suscriba hasta que haya inicializado los elementos. Yo preferiría el evento Load (OnLoad, en realidad). –

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

Uso un temporizador para resolver este problema. Habilite el temporizador mediante el evento ItemCheck. Actúa en el evento Timer's Tick.

Esto funciona si el elemento se comprueba con un clic del mouse o presionando la barra espaciadora. Aprovecharemos el hecho de que el artículo que acaba de marcarse (o no) siempre es el Elemento seleccionado.

El intervalo del temporizador puede ser tan bajo como 1. Para cuando se produce el evento Tick, se establece el nuevo estado comprobado.

Este código de VB.NET muestra el concepto. Hay muchas variaciones que puede emplear. Es posible que desee aumentar el intervalo del temporizador para permitir al usuario cambiar el estado de verificación en varios elementos antes de tomar medidas. Luego, en el evento Tick, realice un pase secuencial de todos los elementos

en la Lista o use su colección CheckedItems para tomar las medidas apropiadas.

Es por eso que primero desactivamos el temporizador en el evento ItemCheck. Desactivar y Activar hace que el período de intervalo vuelva a iniciarse.

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

Basado en Hans Passant's answer Estoy añadiendo una versión genérica VB.NET. Necesitaba un método que se llamaría para todos los controles CheckedListBox en el formulario. Puede modificar esto fácilmente si necesita métodos separados para cada control (sin embargo, agrega algo de redundancia).

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 
Cuestiones relacionadas