La respuesta a esta pregunta radica en cómo funcionan los controles de C #
Los controles en Windows Forms están vinculados a un subproceso específico y no son seguros para subprocesos. Por lo tanto, si está llamando al método de un control desde un subproceso diferente, debe utilizar uno de los métodos de invocación del control para calcular la llamada al subproceso adecuado. Esta propiedad se puede usar para determinar si debe llamar a un método de invocación, lo que puede ser útil si no sabe qué subproceso posee un control.
Desde Control.InvokeRequired
Efectivamente, lo que hace Invoke es garantizar que el código al que está llamando se produzca en el subproceso en el que el control "sigue vivo" y previene de manera eficaz las excepciones entre subprocesos.
Desde una perspectiva histórica, en .Net 1.1, esto estaba realmente permitido. Lo que significaba es que podía intentar ejecutar código en el hilo "GUI" desde cualquier hilo en segundo plano y esto funcionaría principalmente. A veces, solo haría que su aplicación se cerrara porque estaba interrumpiendo efectivamente el hilo de la GUI mientras hacía otra cosa. Esta es la excepción de subprocesos cruzados : imagine intentar actualizar un TextBox mientras la GUI está pintando algo más.
- ¿Qué acción tiene prioridad?
- ¿Es posible que ambos sucedan a la vez?
- ¿Qué sucede con todos los demás comandos que la GUI necesita para ejecutarse?
Efectivamente, estás interrumpiendo una cola, lo que puede tener muchas consecuencias imprevistas. Invoke es efectivamente la forma "educada" de obtener lo que desea hacer en esa cola, y esta regla se aplicó desde .Net 2.0 en adelante mediante una InvalidOperationException lanzada .
Para comprender lo que está sucediendo realmente detrás de escena y lo que se entiende por "hilo de interfaz gráfica de usuario", es útil comprender qué es una bomba de mensajes o un bucle de mensajes.
En realidad, esto ya está respondido en la pregunta " ¿Qué es una bomba de mensajes? " Y se recomienda leerlo para comprender el mecanismo real al que se está vinculando al interactuar con los controles.
Otras lecturas que pueden resultarle útiles incluyen:
¿Qué pasa con Begin Invoke?
Una de las reglas fundamentales de la programación de la GUI de Windows es que solo el hilo que creó un control puede acceder y / o modificar su contenido (excepto por unas pocas excepciones documentadas). Intente hacerlo desde cualquier otro hilo y obtendrá un comportamiento impredecible que va desde punto muerto, excepciones y una interfaz de usuario medio actualizada. La forma correcta de actualizar un control desde otro hilo es publicar un mensaje apropiado en la cola de mensajes de la aplicación. Cuando la bomba de mensajes llegue a ejecutar ese mensaje, el control se actualizará, en el mismo hilo que lo creó (recuerde, la bomba de mensajes se ejecuta en el hilo principal).
y, para una descripción general más pesada de código con una muestra representativa:
Operaciones de subprocesos cruzados no válidas
public delegate void ControlStringConsumer(Control control, string text);
public void SetText(Control control, string text) {
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});
} else {
control.Text=text;
}
}
Una vez que haya comprendido InvokeRequired, es posible que desee considerar el uso de un método de extensión para finalizar estas llamadas. Esto se trata hábilmente en la pregunta de desbordamiento de pila . Se requiere limpieza de código lleno de invocación .
También hay un escrito adicional de lo que sucedió históricamente que puede ser de interés.