Acabo de tropezar con el mismo problema y encontré información interesante y quería poner mi granito de arena y agregarlo aquí.
En primer lugar, como otros ya han mencionado, las operaciones de larga duración deben hacerse mediante un hilo, que puede ser un trabajador de fondo, un hilo explícito, un hilo del threadpool o (desde .Net 4.0) una tarea : Stackoverflow 570537: update-label-while-processing-in-windows-forms, para que la interfaz de usuario se mantenga receptiva.
Pero para tareas cortas no hay una necesidad real de enhebrar, aunque no duele, por supuesto.
He creado un WinForm con un botón y una etiqueta para analizar este problema:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
label1->Text = "Start 1";
label1->Update();
System::Threading::Thread::Sleep(5000); // do other work
}
Mi análisis fue pasando por encima del código (utilizando F10) y ver lo que pasó. Y después de leer este artículo Multithreading in WinForms he encontrado algo interesante. El artículo dice en la parte inferior de la primera página, que el subproceso de la interfaz de usuario no puede volver a pintar la interfaz de usuario hasta que la función ejecutada actualmente finalice y la ventana esté marcada por Windows como "no responde" en su lugar después de un tiempo. También he notado eso en mi solicitud de prueba desde arriba mientras lo paso, pero solo en ciertos casos.
(Para la siguiente prueba es importante no tener Visual Studio configurado en pantalla completa, debe poder ver la ventana de su pequeña aplicación al mismo tiempo al lado, No debe tener que cambiar entre la ventana de Visual Studio para la depuración y la ventana de aplicación para ver qué pasa. iniciar la aplicación, establecer un punto de interrupción en label1->Text ...
, poner la ventana de la aplicación junto a la ventana VS y coloque el cursor del ratón sobre la ventana de VS.)
Cuando hago clic una vez en VS después del inicio de la aplicación (para poner los focos allí y permitir el paso) y páselo SIN mover el mouse, se establece el nuevo texto y se actualiza la etiqueta en la función de actualización(). Esto significa que la IU está repintada obviamente.
Cuando paso sobre la primera línea, muevo el mouse alrededor y hago clic en algún lugar, luego paso más, es probable que el nuevo texto esté activado y se llame a la función update(), pero la UI no se actualiza/repintado y el texto anterior permanece allí hasta que finaliza la función button1_click(). ¡En lugar de repintar, la ventana está marcada como "no receptiva"! Tampoco ayuda agregar this->Update();
para actualizar el formulario completo.
Agregar Application::DoEvents();
le da a la interfaz de usuario la oportunidad de actualizar/volver a pintar. De todos modos, debes tener cuidado de que el usuario no pueda presionar botones ni realizar otras operaciones en la interfaz de usuario que no están permitidas. Por lo tanto: Try to avoid DoEvents()!, mejor uso de subprocesos (que creo que es bastante simple en .Net).
Pero (@Jagd, 2 de abril de 2010 a las 19:25) puede omitir .refresh()
y .invalidate()
.
Mis explicaciones son las siguientes: AFAIK winform todavía utiliza la función WINAPI. También MSDN article about System.Windows.Forms Control.Update method se refiere a la función WMAPI WM_PAINT. El MSDN article about WM_PAINT indica en su primera oración que el comando WM_PAINT solo es enviado por el sistema cuando la cola de mensajes está vacía. Pero como la cola de mensajes ya está llena en el segundo caso, no se envía y, por lo tanto, la etiqueta y el formulario de solicitud no se vuelven a pintar.
<> broma> Conclusión: por lo que sólo tiene que mantener al usuario utilizar el ratón ;-) <>/broma>
Ejecutar 'SomewhatLongRunningOperation()' en otro hilo es la respuesta correcta aquí. No debe atar el hilo de la interfaz de usuario para nada que no afecte directamente a la IU. En cuanto a la simplificación del código, es muy posible que puedas simplificar el uso de ese otro hilo. – cHao