net - checklist c#
Cómo detectar si los elementos se agregan a un control ListBox(o CheckedListBox) (4)
Esto parece una pregunta fundamentalmente simple. Tengo un cuadro de diálogo WinForms con un cuadro de lista. Este control no se completa mediante el enlace de datos, pero está lleno de llamadas a
listBox.Items.Add (obj);
Es posible que esta llamada se pueda realizar de forma asíncrona desde varios lugares y me gustaría conectar el cuadro de lista y observar los cambios en los miembros de sus datos para poder realizar otros cambios en la interfaz de usuario (como habilitar o deshabilitar los controles que interactúan con el cuadro de lista). en el número de elementos en la lista).
Desafortunadamente, a menos que esté completamente despistado, no parece haber un evento o método virtual que pueda engancharse para detectar esto. Puedo enganchar para cambios seleccionados y (para CheckedListBox) puedo enganchar para cambios en el estado de verificación. Pero no por los cambios en la recopilación de datos subyacentes.
Sé que esto es posible en Win32 (hay un mensaje de ventana para esto). ¿Qué me estoy perdiendo?
[Editado por Simon]
Solución
Me señalaron la solución correcta (que he marcado como la respuesta aceptada) que consiste en anular el método WndProc del ListBox y manejar los mensajes del cuadro de lista manualmente. Aquí está la solución que decidí (y funciona). Podría modificarse para proporcionar más detalles en el evento, o dividir los mensajes en eventos separados, pero para mis necesidades esto es suficiente.
using System;
using System.Windows.Forms;
public class CheckedListBoxEx : CheckedListBox
{
public CheckedListBoxEx() { }
private const int LB_ADDSTRING = 0x180;
private const int LB_INSERTSTRING = 0x181;
private const int LB_DELETESTRING = 0x182;
private const int LB_RESETCONTENT = 0x184;
protected override void WndProc(ref Message m)
{
if (m.Msg == LB_ADDSTRING ||
m.Msg == LB_INSERTSTRING ||
m.Msg == LB_DELETESTRING ||
m.Msg == LB_RESETCONTENT)
{
ItemsChanged(this, EventArgs.Empty);
}
base.WndProc(ref m);
}
public event EventHandler ItemsChanged = delegate { };
}
Desafortunadamente, no hay una manera fácil de hacer esto usando herencia o eventos. Debería poder anular el método Agregar de la clase Artículos, ¡pero no puede acceder a él! Es posible que pueda interceptar el bucle de mensajes para averiguar cuándo está sucediendo esto, pero eso está más allá de mi experiencia.
Una cosa que noté de tu pregunta es que mencionas que los elementos se están agregando de forma asíncrona. No hagas eso Su problema puede resolverse si sincroniza en el hilo del formulario (si su problema es que el control no se está actualizando).
Esta solución parece funcionar; en mi situación, la implementé en VB. Acabo de crear una clase ExtendedListbox que hereda el control listbox, implementa INotifyPropertyChanged y sombrea la propiedad Items.
Imports System.ComponentModel
Public Class ExtendedListBox:Inherits ListBox:Implements INotifyPropertyChanged
Public Shadows Property Items() As ObjectCollection
Get
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Items"))
Return MyBase.Items
End Get
Set(value As ObjectCollection)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Items"))
MyBase.Items.Clear()
For Each o As Object In value
MyBase.Items.Add(o)
Next
End Set
End Property
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
No conozco ningún evento que pueda ver para mostrar que un elemento se ha agregado a un ListBox. Quizás pueda usar el método Win32 que describió en su lugar (es decir, agarre un manejador, use WndProc, etc.).
Alternativamente, quizás puedas usar otra clase que agregue elementos en su lugar. Por ejemplo, en lugar de llamar directamente al método Agregar en el ListBox, podría hacer que las acciones del usuario llamen al método Agregar dentro de la nueva clase, que luego agrega el elemento al ListBox. Puede establecer un evento dentro de esa clase que le permita ver lo que se ha agregado.
También me gusta la idea de subclasificar el ListBox como lo menciona otro póster ...