Me he dado cuenta de cuán a menudo es necesario escribir el siguiente patrón de código en el código GUI controlado por eventos, donde
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
se convierte en:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
Este es un patrón incómodo en C #, tanto para recordar como para escribir. ¿Alguien ha encontrado algún tipo de atajo o construcción que automatice esto hasta cierto punto? Sería genial si hubiera una manera de adjuntar una función a los objetos que realiza esta comprobación sin tener que pasar por todo este trabajo adicional, como un object1.InvokeIfNecessary.visible = true
acceso directo de tipo.
Las respuestas anteriores han discutido la impracticabilidad de llamar a Invoke () cada vez, e incluso entonces la sintaxis de Invoke () es ineficiente y aún difícil de manejar.
Entonces, ¿alguien ha descubierto algún atajo?
fuente
object1.InvokeIfNecessary.Visible = true
línea; mira mi respuesta actualizada y déjame saber lo que piensas.Respuestas:
El enfoque de Lee puede simplificarse aún más
Y se puede llamar así
No es necesario pasar el control como parámetro al delegado. C # crea automáticamente un cierre .
ACTUALIZACIÓN :
Según varios otros carteles
Control
se pueden generalizar comoISynchronizeInvoke
:DonBoitnott señaló que, a diferencia de
Control
laISynchronizeInvoke
interfaz, se requiere una matriz de objetos para elInvoke
método como lista de parámetros para elaction
.ACTUALIZACIÓN 2
Ediciones sugeridas por Mike de Klerk (ver comentario en el primer fragmento de código para el punto de inserción):
Consulte el comentario de ToolmakerSteve a continuación para conocer las inquietudes sobre esta sugerencia.
fuente
ISynchronizeInvoke
lugar deControl
? (Felicitaciones a Jon Skeet stackoverflow.com/questions/711408/… )ISynchronizeInvoke
. Pero el único tipo que se deriva de él (según Reflector) esControl
, por lo que la ventaja es limitada.while (!control.Visible) ..sleep..
. Para mí, eso tiene un mal olor de código, ya que es un retraso potencialmente ilimitado (tal vez incluso un bucle infinito en algunos casos), en un código que puede tener llamadas que no esperan ese retraso (o incluso un punto muerto). En mi humilde opinión, cualquier uso deSleep
debe ser responsabilidad de cada persona que llama, O debe estar en un contenedor separado que esté claramente marcado en cuanto a sus consecuencias. En mi humilde opinión, generalmente sería mejor "fallar con fuerza" (excepción, atrapar durante la prueba) o "no hacer nada" si el control no está listo. Comentarios?InvokeRequired
indica si el hilo de llamada es diferente del hilo que creó el control.Invoke
pasa la acción del hilo de llamada al hilo del control donde se ejecuta. Esto garantiza que, por ejemplo, un controlador de eventos de clic nunca se interrumpa.Podrías escribir un método de extensión:
Y úsalo así:
EDITAR: Como Simpzon señala en los comentarios, también puede cambiar la firma a:
fuente
Aquí está el formulario que he estado usando en todo mi código.
He basado esto en la entrada del blog aquí . No me ha fallado este enfoque, por lo que no veo ninguna razón para complicar mi código con un control de la
InvokeRequired
propiedad.Espero que esto ayude.
fuente
InvokeRequired
si el código se puede ejecutar antes de que se muestre el control o tendrá una excepción fatal.Cree un archivo ThreadSafeInvoke.snippet, y luego puede seleccionar las declaraciones de actualización, hacer clic derecho y seleccionar 'Rodear con ...' o Ctrl-K + S:
fuente
Aquí hay una versión mejorada / combinada de las respuestas de Lee, Oliver y Stephan.
La plantilla permite un código flexible y sin conversión que es mucho más legible, mientras que el delegado dedicado proporciona eficiencia.
fuente
Prefiero usar una sola instancia de un método Delegado en lugar de crear una nueva instancia cada vez. En mi caso, solía mostrar mensajes de progreso y (información / error) de un Backroundworker copiando y enviando datos grandes desde una instancia de SQL. Mientras tanto, después de aproximadamente 70000 llamadas de progreso y mensajes, mi formulario dejó de funcionar y mostraba nuevos mensajes. Esto no ocurrió cuando comencé a usar un solo delegado de instancia global.
fuente
Uso:
Código:
fuente
Me gusta hacerlo un poco diferente, me gusta llamarme a mí mismo si es necesario con una Acción,
este es un patrón útil, IsFormClosing es un campo que configuro en True cuando estoy cerrando mi formulario, ya que puede haber algunos subprocesos en segundo plano que todavía se están ejecutando ...
fuente
Nunca deberías escribir código que se vea así:
Si tiene un código que se ve así, entonces su aplicación no es segura para subprocesos. Significa que tiene un código que ya está llamando a DoGUISwitch () desde un hilo diferente. Es demasiado tarde para verificar si está en un hilo diferente. InvokeRequire debe llamarse ANTES de hacer una llamada a DoGUISwitch. No debe acceder a ningún método o propiedad desde un hilo diferente.
Referencia: Control.InvokeRequired Propiedad donde puede leer lo siguiente:
En una arquitectura de CPU única no hay problema, pero en una arquitectura de CPU múltiple puede hacer que parte del subproceso de la interfaz de usuario se asigne al procesador donde se estaba ejecutando el código de llamada ... y si ese procesador es diferente de donde el subproceso de la interfaz de usuario se estaba ejecutando cuando finaliza el subproceso de llamada. Windows pensará que el subproceso de la interfaz de usuario ha finalizado y eliminará el proceso de la aplicación, es decir, su aplicación se cerrará sin errores.
fuente
invoke()
et al antes de que se le dé un control al control, pero en mi humilde opinión, no describe lo que ha descrito. El punto de todas estasinvoke()
tonterías es actualizar la interfaz de usuario de una manera segura para subprocesos, y creo que poner más instrucciones en un contexto de bloqueo conduciría a la tartamudez. (Ugh ... me alegro de haber dejado de usar M $ tech. ¡Tan complicado!)