c# ejemplo - Invoke(Delegate)





thread windows (9)


Invoque ((MethodInvoker) delegate {textBox1.Text = "Test";});

¿Alguien puede explicar esta declaración escrita en este link

Invoke(Delegate):

Ejecuta el delegado especificado en el subproceso que posee el identificador de ventana subyacente del control.

¿Alguien puede explicar lo que esto significa (especialmente el audaz) no puedo entenderlo claramente?




Significa que el delegado que pasa se ejecuta en el hilo que creó el objeto Control (que es el hilo de UI).

Debe llamar a este método cuando la aplicación tiene varios subprocesos y desea realizar alguna operación de interfaz de usuario a partir de un subproceso que no sea el de la interfaz de usuario, ya que si intenta llamar a un método de un control desde un subproceso diferente, obtendrá un System.InvalidOperationException.




Significa que el delegado se ejecutará en el subproceso UI, incluso si llama a ese método desde un subprocesador o subproceso de grupo de subprocesos. Los elementos de la interfaz de usuario tienen afinidad por el hilo : 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 ventana. Pero todo eso es un detalle de implementación.

El punto clave es: llamarás a este método desde un hilo de trabajo para que puedas acceder a la interfaz de usuario (para cambiar el valor en una etiqueta, etc.), ya que no puedes hacer eso desde ningún otro hilo que no sea el hilo de la interfaz de usuario.




this.Invoke(delegate) asegúrese de llamar al delegado el argumento para esto. this.Invoke() en el hilo principal / thread creado.

Puedo decir que una regla de Thumb no accede a los controles de tu formulario, excepto desde el hilo principal.

Puede ser 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 a través de las cuales creas un hilo de Threadpool (es decir, 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. Primero, investigue si el hilo en ejecución actual es el hilo principal usando this.InvokeRequired si devuelve true, el código actual se está ejecutando en el hilo del trabajador, así que llame a this.Invoke (d, new object [] {text});

else actualiza directamente el control de la interfaz de usuario (aquí tienes la garantía de que estás ejecutando el código en el hilo principal).




Los delegados son esencialmente Action línea o Func<T> . Puede declarar un delegado fuera del alcance de un método que esté ejecutando o utilizando una expresión lambda ( => ); porque 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);
}



La respuesta a esta pregunta radica en cómo funcionan los controles C #

Los controles en Windows Forms están vinculados a un hilo específico y no son seguros para subprocesos. Por lo tanto, si llama a un método de control desde un hilo diferente, debe usar uno de los métodos de invocación del control para ordenar la llamada al hilo apropiado. Esta propiedad se puede usar para determinar si debe invocar un método de invocación, lo que puede ser útil si no sabe qué hilo posee un control.

De msdn.microsoft.com/en-us/library/…

Efectivamente, lo que hace Invoke es asegurar que el código que está llamando ocurra en el hilo que el control "conserva" evitando de manera efectiva las excepciones de hilos cruzados.

Desde una perspectiva histórica, en .Net 1.1, esto fue permitido. Lo que significa es que puedes probar y ejecutar código en el hilo "GUI" desde cualquier hilo de fondo y esto funcionaría principalmente. En ocasiones, solo causaba que tu aplicación salga porque efectivamente estabas interrumpiendo el hilo de la GUI mientras hacía otra cosa. Esta es la excepción cruzada : imagine intentar actualizar un cuadro de texto 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 otros comandos que la GUI necesita para ejecutarse?

De hecho, estás interrumpiendo una cola, que puede tener muchas consecuencias imprevistas. Invocar es efectivamente la forma "cortés" de obtener lo que desea hacer en esa cola, y esta regla se impuso desde .Net 2.0 en adelante a través de una InvalidOperationException lanzada.

Para comprender lo que sucede realmente detrás de escena, y lo que se entiende por "Subproceso GUI", es útil comprender qué es un Message Pump o Message Loop.

Esto ya está respondido en la pregunta " ¿Qué es una bomba de mensaje? " Y es una lectura recomendada para comprender el mecanismo real que está atando al interactuar con los controles.

Otras lecturas que puede encontrar útiles incluyen:

¿Qué pasa con Begin Invoke?

Una de las reglas cardinales de la programación de GUI de Windows es que solo el hilo que creó un control puede acceder y / o modificar su contenido (excepto por algunas excepciones documentadas). Intente hacerlo desde cualquier otro hilo y obtendrá un comportamiento impredecible que puede ir desde un punto muerto hasta excepciones a una interfaz de usuario medio actualizada. Entonces, 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 se pone 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 vista general de más código con una muestra representativa:

Operaciones de hilos cruzados invá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 tenga aprecio por InvokeRequired, puede considerar usar un método de extensión para envolver estas llamadas. Esto está perfectamente cubierto en la pregunta sobre desbordamiento de pila. Código de limpieza llenado con la invocación requerida .

También hay una descripción adicional de lo que sucedió históricamente que puede ser de interés.




En términos prácticos, significa que se garantiza que el delegado se invoque 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)
}



Si desea modificar un control, debe hacerlo en la secuencia en la que se creó el control. Este método Invoke permite ejecutar métodos en el hilo asociado (el hilo que posee el identificador de ventana subyacente del control).

En el ejemplo siguiente thread1 arroja una excepción porque SetText1 está tratando de modificar textBox1.Text de otro hilo. Pero en thread2, la acción en SetText2 se ejecuta en el hilo en el que se creó el cuadro de texto

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"));
}



Delegate.BeginInvoke () pone en cola de forma asíncrona la llamada de un delegado y devuelve el control inmediatamente. Cuando use Delegate.BeginInvoke (), debe llamar a Delegate.EndInvoke () en el método de devolución de llamada para obtener los resultados.

Delegate.Invoke () llama sincrónicamente al delegado en el mismo hilo.

Artículo de MSDN







c# winforms delegates invoke