Por qué no controlará la actualización / actualización a mitad de proceso

Tengo un formulario de Windows (C # .NET) con una etiqueta de estado que parece que no puedo actualizar en el medio de un proceso en los métodos del controlador de eventos. Mi código se ve así …

void Process_Completed(object sender, EventArgs e) { string t = "Process is finished!"; this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t }); } void Process_Started(object sender, EventArgs e) { string t = "Process has begun"; this.Invoke(new StatusLabelUpdator(updateStatusLabel), new object[] { t }); } private delegate void StatusLabelUpdator(string text); private void updateStatusLabel(string text) { StatusLabel1.Text = text; statusStrip1.Invalidate(); statusStrip1.Refresh(); statusStrip1.Update(); } 

Cuando ejecuto el código, una vez que se inicia el proceso, se desencadena el método Process_Started, y un par de segundos más tarde se desencadena el método Process_Completed. Por algún motivo, no puedo conseguir que la etiqueta de estado muestre siempre “El proceso ha comenzado”. ¡Solo muestra “El proceso ha terminado!”. Como puede ver, he intentado invalidar, actualizar y actualizar la lista de estado que contiene la etiqueta de estado, pero no ha tenido éxito. No puedo llamar a update / refresh / invalidate en la etiqueta de estado porque esos métodos no están disponibles. ¿Qué estoy haciendo mal?

INFORMACIÓN AÑADIDA

El “proceso” se inicia con un clic en el formulario que llama a un método en una clase separada que se ve así:

 public void DoSomeProcess() { TriggerProcessStarted(); System.Threading.Thread.Sleep(2000); // For testing.. TriggerProcessComplete(); } 

y dentro de los métodos TriggerProcessxxxx, disparo los eventos usando este código …

 var EventListeners = EH.GetInvocationList(); //EH is the appropriate EventHandler if (EventListeners != null) { for (int index = 0; index < EventListeners.Count(); index++) { var methodToInvoke = (EventHandler)EventListeners[index]; methodToInvoke.BeginInvoke(this, EventArgs.Empty, EndAsyncEvent, new object[] { }); } } 

Finalmente, agregué Application.DoEvents() al método updateStatusLabel pero no ayudó. Todavía estoy obteniendo el mismo resultado. Aquí está mi método de actualización.

 private void updateStatusLabel(string text) { StatusLabel1.Text = text; statusStrip1.Refresh(); Application.DoEvents(); } 

Así que supongo que el “procesamiento” tiene lugar en el hilo de la interfaz de usuario, pero el controlador de eventos se invoca en su propio hilo, que luego invoca la actualización de control en el hilo de la interfaz de usuario. ¿Es esta una forma tonta de hacer las cosas? Nota: La clase que contiene el método DoSomeProcess () está en una .NET ClassLibrary separada a la que me refiero.

Si está procesando en el hilo de UI, no podrá hacer nada más (como volver a dibujar tags actualizadas) mientras se está ejecutando el procesamiento. Entonces, por ejemplo, si el procesamiento está sucediendo porque el usuario hizo clic en un botón y se activa con el botón clic en el controlador (sin colocarlo explícitamente en otro hilo), se está ejecutando en el hilo de la interfaz de usuario. Aunque actualice el texto de la etiqueta, no se dibujará hasta que reciba un mensaje de pintura, en cuyo punto probablemente esté ocupado haciendo su procesamiento.

La respuesta es hacer un procesamiento de larga duración en un hilo separado . El truco (en mi humilde opinión) es usar Application.DoEvents para permitir que el subproceso de la interfaz de usuario haga algunas cosas de UI durante su procesamiento. Si coloca uno de ellos después de actualizar la etiqueta y antes de comenzar su procesamiento, las probabilidades son bastante altas, la etiqueta se volverá a pintar. Pero luego, durante el procesamiento, no se pueden procesar más eventos de pintura (lo que lleva a ventanas a medio dibujar cuando alguien mueve otra ventana de la aplicación sobre su aplicación y viceversa, etc.). Por lo tanto, lo llamo hack (aunque, eh, um, he sido conocido por hacerlo :-)).

Edite la actualización según sus ediciones:

Re

Así que supongo que el “procesamiento” está teniendo lugar en el hilo de la interfaz de usuario, pero el controlador de eventos se invoca en su propio hilo …

Supongo que DoSomeProcess se desencadena desde el hilo de la interfaz de usuario (por ejemplo, en respuesta directa a un clic de botón o similar). Si es así, entonces sí, su procesamiento definitivamente está en el hilo de UI. Debido a que TriggerProcessStarted activa su callback de manera asincrónica a través de BeginInvoke , no tiene idea de cuándo se ejecutará, pero en cualquier caso su código se inicia inmediatamente en el procesamiento, nunca cediendo, por lo que nadie más será capaz de tomar ese hilo. Dado que ese es el hilo de UI, la llamada al delegado bloqueará en la llamada Invoke el texto de la etiqueta, luego de lo cual tendrá que esperar el hilo de UI (que está ocupado procesando). (Y eso suponiendo que esté progtwigdo en un hilo diferente; no podría convencerme al 100% de ninguna manera, porque Microsoft tiene dos BeginInvoke diferentes, que IIRC uno de los diseñadores ha reconocido que era una Idea realmente tonta, y ha sido un mientras que luché con esto.)

Si hace que las llamadas TriggerProcessStarted a sus callbacks sean sincronizadas, debería estar bien. Pero idealmente, programe el procesamiento (si no está haciendo UI) en su propio subproceso.