2009-10-29 16 views
60

Recientemente comencé a programar en WPF y tropecé con el siguiente problema. No entiendo cómo usar el método Dispatcher.Invoke(). Tengo experiencia en el roscado y he hecho unos simples de Windows Forms programas en los que acabo de utilizar elCambie los controles WPF de un hilo no principal usando Dispatcher.Invoke

Control.CheckForIllegalCrossThreadCalls = false; 

Sí sé que es bastante escaso pero éstos eran simples aplicaciones de monitoreo.

El hecho es que ahora estoy haciendo una aplicación WPF que recupera datos en segundo plano, comienzo un nuevo hilo para hacer la llamada para recuperar los datos (de un servidor web), ahora quiero mostrarlo en mi WPF formar. La cuestión es que no puedo establecer ningún control desde este hilo. Ni siquiera una etiqueta ni nada. ¿Como puede ésto ser resuelto?

Respuesta comentarios:
@Jalfp:
lo tanto, utilizar este método despachador en la 'nueva banda de rodadura' cuando llegue a los datos? ¿O debería hacer que un trabajador de fondo recupere los datos, los coloque en un campo y comience un nuevo hilo que espere hasta que se llene este campo y llame al despachador para mostrar los datos recuperados en los controles?

Respuesta

145

Lo primero es comprender que el Dispatcher no está diseñado para ejecutar operaciones de bloqueo prolongadas (como recuperar datos de un servidor web ...). Puede usar Dispatcher cuando desee ejecutar una operación que se ejecutará en el hilo de la interfaz de usuario (por ejemplo, actualizar el valor de una barra de progreso).

Lo que puede hacer es recuperar sus datos en un trabajador en segundo plano y usar el método ReportProgress para propagar los cambios en el hilo de la interfaz de usuario.

Si realmente necesita usar el despachador directamente, es bastante simple:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => this.progressBar.Value = 50)); 
+19

Usted puede deshacerse de la 'nueva acción (' parte, y sólo tiene que utilizar una expresión lambda: DispatcherPriority.Background,() => = 50 this.progressBar.Value – jrista

+0

Sí No sé por qué pongo una Acción aquí: p – japf

+0

Entonces, ¿utilizo este método Dispatcher en la 'nueva banda de rodadura' cuando obtengo los datos? O debería hacer que un trabajador de fondo recupere los datos, los coloque en un campo y comience un nuevo hilo que espere hasta que este campo esté lleno y llame al despachador para mostrar los datos recuperados en los controles? –

19

japf tiene conteste correctamente. En caso de que estés mirando acciones de varias líneas, puedes escribir lo siguiente.

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, 
    new Action(() => { 
    this.progressBar.Value = 50; 
    })); 

Información para otros usuarios que quieren saber sobre el rendimiento:

si su necesidad de código que se ha escrito para un alto rendimiento, se puede comprobar primero si la invocación es requerido por el uso de la bandera CheckAccess.

if(Application.Current.Dispatcher.CheckAccess()) 
{ 
    this.progressBar.Value = 50; 
} 
else 
{ 
    Application.Current.Dispatcher.BeginInvoke(
     DispatcherPriority.Background, 
     new Action(() => { 
     this.progressBar.Value = 50; 
     })); 
} 

Tenga en cuenta que el método CheckAccess() se oculta a Visual Studio 2015 por lo que acaba de escribir sin esperar IntelliSense para mostrar para arriba. Tenga en cuenta que CheckAccess tiene una sobrecarga en el rendimiento (sobrecarga en pocos nanosegundos). Solo es mejor cuando desea guardar ese microsegundo requerido para realizar la 'invocación' a cualquier costo. Además, siempre hay una opción para crear dos métodos (activado con invocación y otro sin) cuando el método de llamada es seguro si está en UI Thread o no. Es raro que ocurra un caso raro cuando debería estar mirando este aspecto del despachador.

Cuestiones relacionadas