2011-05-30 11 views
5

Estoy modificando una aplicación escrita en C# que hace un uso intensivo de multi-threading para reproducir archivos de audio y mostrar imágenes a un usuario. Dado que tiene múltiples subprocesos, necesito usar el método Invoke a menudo para cambiar los elementos del formulario. Me encuentro con un patrón con el que no me siento cómodo, en el que me encuentro escribiendo métodos frecuentes, pequeños y delegados que generalmente solo hacen una cosa. Un ejemplo de esto es la siguiente:¿Qué se considera una buena práctica de programación en aplicaciones winform de subprocesos múltiples con uso de delegado?

delegate void setImageCallback(Image img); 
private void setImage(Image img) 
{ 
    this.pictureBox1.Image = img; 
} 

private void someOtherMethod() 
{ 
    ... 
    if (this.pictureBox1.InvokeRequired) 
    { 
     this.Invoke(new setImageCallback(setImage), Image.FromFile("example.png"); 
    } 
    else 
    { 
     this.pictureBox1.Image = Image.FromFile("example.png"); 
    } 
    ... 
} 

¿Cómo la gente en general manejar estas situaciones, por lo que no se encuentra escribiendo un absurdo número de delegados y métodos sólo para seguir siendo seguro para subprocesos? Obviamente, la consolidación de métodos similares es excelente, pero si potencialmente necesito actualizar cada elemento del formulario en mi formulario, no quiero tener un delegado y método de "modificación" para cada uno de estos.

Gracias.

+0

http://stackoverflow.com/questions/2367718/c-automating-the-invokerequired-code- patrón/2367888 # 2367888 –

Respuesta

6

Usted definitivamente no necesita un delegado por separado para cada uno. Puede utilizar Action delegados y expresiones lambda para simplificarlo, así:

private void SomeOtherMethod() 
{ 
    Action action =() => pictureBox1.Image = Image.FromFile("example.png"); 
    if (pictureBox1.InvokeRequired) 
    { 
     Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

O puede separar el cheque if declaración y InvokeRequired y generalizar aún más, como esto:

public static void InvokeIfRequired(Control control, Action action) 
{ 
    if (control.InvokeRequired) 
    { 
     control.Invoke(action); 
    } 
    else 
    { 
     action(); 
    } 
} 

private void SomeOtherMethod() 
{ 
    InvokeIfRequired(() => pictureBox1.Image = Image.FromFile("example.png"); 
} 
+0

Eso es interesante ... ¿eso es típicamente lo que se hace en "empresa"? Además, por curiosidad ... ¿qué pasaría si usaras Invoke cuando no fuera necesario? ¿Simplemente estarías haciendo llamadas a métodos innecesarios y aumentando la sobrecarga, o eso viola la seguridad de las hebras? – rybosome

+0

Solía ​​tener un método exactamente así en mi biblioteca miscelánea (el mismo nombre también), pero lo tenía como método de extensión. Muy útil. Aunque prefiero la forma en que lo hice a continuación en estos días. Aún así, +1. –

+0

@Ryan, cuando llama a 'Invoke', el delegado se coloca en la cola de mensajes de los controles y luego la persona que llama espera hasta que se ejecuta. Puede hacer lo mismo sin esperar llamando a 'BeginInvoke', que probablemente sea mejor en la mayoría de los casos. Llamar a 'Invoke' innecesariamente puede causar que las acciones se retrasen ya que se agregan a la cola de mensajes en lugar de procesarse inmediatamente. Es probable que no se note, pero sigue siendo una carga innecesaria. –

8

Un buen ejemplo es here.

this.BeginInvoke((Action) (()=> 
    { 
     pictureBox1.Image = Image.FromFile("example.png"); 
    })); 
+0

Las instrucciones para hacer una búsqueda en realidad no constituyen una buena respuesta. Si solo edita y saca la parte "hacer una búsqueda en google", sería mejor. –

+0

Ok lo quité ... Iba a escribir un ejemplo, pero estoy cocinando algo ... eso fue lo mejor que pude hacer rápidamente sin quemar mi comida;) –

+0

definitivamente no quiero que te quemes tu comida. :-) Gracias por actualizar, su respuesta es mucho mejor ahora. –

1

I usaría el tipo MethodInvoker junto con un método anónimo o una expresión lambda. También me construir la lógica invocación en el propio método, en lugar de utilizar un método seguro para subprocesos separado:

void SomeMethod(/* with whatever args */) { 
    if (InvokeRequired) 
     Invoke(new MethodInvoker(() => SomeMethod(/* args used to call method */))); 
    else 
     // the method body itself 
} 
Cuestiones relacionadas