¿Alguien puede explicar esta declaración escrita en este enlace?
Invoke(Delegate):
Ejecuta el delegado especificado en el subproceso que posee el identificador de ventana subyacente del control.
¿Alguien puede explicar qué significa esto (especialmente el en negrita)? No puedo entenderlo claramente
Respuestas:
La respuesta a esta pregunta radica en cómo funcionan los controles de C #
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.
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?
y, para una descripción general más pesada de código con una muestra representativa:
Operaciones de subprocesos cruzados no válidas
// the canonical form (C# consumer) public delegate void ControlStringConsumer(Control control, string text); // defines a delegate type public void SetText(Control control, string text) { if (control.InvokeRequired) { control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself } else { control.Text=text; // the "functional part", executing only on the main thread } }
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.
fuente
Un control o un objeto de ventana en Windows Forms es solo un envoltorio alrededor de una ventana de Win32 identificada por un identificador (a veces llamado HWND). La mayoría de las cosas que hace con el control eventualmente resultarán en una llamada a la API de Win32 que usa este identificador. El identificador es propiedad del hilo que lo creó (normalmente el hilo principal) y no debe ser manipulado por otro hilo. Si por alguna razón necesita hacer algo con el control de otro hilo, puede usar
Invoke
para pedirle al hilo principal que lo haga en su nombre.Por ejemplo, si desea cambiar el texto de una etiqueta de un hilo de trabajo, puede hacer algo como esto:
theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
fuente
this.Invoke(() => this.Enabled = true);
Todo lo que sethis
refiere seguramente está en el hilo actual, ¿verdad?Si desea modificar un control debe hacerlo en el hilo en el que se creó el control. Este
Invoke
método le permite ejecutar métodos en el hilo asociado (el hilo que posee el identificador de ventana subyacente del control).En el ejemplo siguiente thread1 lanza una excepción porque SetText1 está intentando modificar textBox1.Text de otro hilo. Pero en thread2, Action en SetText2 se ejecuta en el hilo en el que se creó TextBox
private void btn_Click(object sender, EvenetArgs e) { var thread1 = new Thread(SetText1); var thread2 = new Thread(SetText2); thread1.Start(); thread2.Start(); } private void SetText1() { textBox1.Text = "Test"; } private void SetText2() { textBox1.Invoke(new Action(() => textBox1.Text = "Test")); }
fuente
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
fuente
En términos prácticos, significa que se garantiza que el delegado se invocará en el hilo principal. Esto es importante porque en el caso de los controles de Windows, si no actualiza sus propiedades en el hilo principal, entonces no ve el cambio o el control genera una excepción.
El patrón es:
void OnEvent(object sender, EventArgs e) { if (this.InvokeRequired) { this.Invoke(() => this.OnEvent(sender, e); return; } // do stuff (now you know you are on the main thread) }
fuente
this.Invoke(delegate)
asegúrese de que está llamando al delegado del argumento enthis.Invoke()
el hilo principal / hilo creado.Puedo decir que una regla de pulgar no accede a los controles de su formulario, excepto desde el hilo principal.
Puede que las siguientes líneas tengan sentido para usar Invoke ()
private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } }
Hay situaciones aunque crea un hilo de Threadpool (es decir, un hilo de trabajo) que se ejecutará en el hilo principal. No creará un nuevo hilo porque el hilo principal está disponible para procesar más instrucciones. Así que primero investigue si el hilo actual en ejecución es el hilo principal usando
this.InvokeRequired
if devuelve verdadero el código actual se está ejecutando en el hilo de trabajo así que llame a this.Invoke (d, new object [] {text});de lo contrario, actualice directamente el control de la interfaz de usuario (aquí se le garantiza que está ejecutando el código en el hilo principal).
fuente
Significa que el delegado se ejecutará en el subproceso de la IU, incluso si llama a ese método desde un trabajador en segundo plano o un subproceso de grupo de subprocesos. Los elementos de la interfaz de usuario tienen afinidad por los hilos ; solo les gusta hablar directamente con un hilo: el hilo de la interfaz de usuario. El subproceso de la interfaz de usuario se define como el subproceso que creó la instancia de control y, por lo tanto, está asociado con el identificador de la ventana. Pero todo eso es un detalle de implementación.
El punto clave es: llamaría a este método desde un hilo de trabajo para poder acceder a la interfaz de usuario (para cambiar el valor en una etiqueta, etc.), ya que no puede hacerlo desde ningún otro hilo que no sea el hilo de la interfaz de usuario.
fuente
Los delegados son esencialmente en línea
Action
oFunc<T>
. Puede declarar un delegado fuera del alcance de un método que está ejecutando o usando unalambda
expresión (=>
); debido a que ejecuta el delegado dentro de un método, lo ejecuta en el hilo que se está ejecutando para la ventana / aplicación actual, que es el bit en negrita.Ejemplo de lambda
int AddFiveToNumber(int number) { var d = (int i => i + 5); d.Invoke(number); }
fuente
Significa que el delegado que pasa se ejecuta en el hilo que creó el objeto Control (que es el hilo de la IU).
Debe llamar a este método cuando su aplicación es multiproceso y desea realizar alguna operación de IU desde un subproceso que no sea el subproceso de la IU, porque si solo intenta llamar a un método en un Control desde un subproceso diferente, obtendrá un System.InvalidOperationException.
fuente