2010-02-05 10 views
6

Tengo un programa con un mapa de Geospace incrustado en él. El manejo de eventos para el mapa se maneja en un hilo separado para mantener el mapa sensible (por ejemplo, los eventos que se disparan cuando se hace clic en el mapa).C#, WPF, llama automáticamente a Dispatcher. ¿Invoca cuando es necesario?

El problema que tengo es cuando el mapa dispara un evento, mi programa necesita actualizar algunas cosas en su interfaz gráfica de usuario, y también vuelve a llamar al mapa para manejar la colocación de imágenes en el mapa.

Intenté envolver todo el método del controlador de eventos en this.Dispatcher.Invoke, lo que me devuelve al hilo principal de la IU. Esto funciona muy bien para actualizar mi GUI, pero cuando vuelvo a llamar al mapa, todavía estoy en el hilo de UI que puede causar algunos problemas en el mapa.

Básicamente, para que esto funcione, voy a tener que ejecutar dispatcher.invoke cada vez que quiero cambiar un control en mi interfaz gráfica de usuario. ¿Hay alguna manera de que pueda hacer esto automáticamente sin envolver cada llamada en dispatcher.invoke? Espero que todo esto tenga sentido.

Heres un código de ejemplo para el evento que estoy hablando ..

private void Map_OnMapClicked(object sender, MapClickedEventArgs e) 
    { 
     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 

     Map.DoSomethingInTheMap(); 

     this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      // Do something to update my gui 
     })); 


     //etc etc etc 
    } 

Respuesta

6

Si usted necesita para mantener cada operación respectiva en su propio contexto de sincronización, esto es, por desgracia el mejor enfoque. Tendrá que invocar con el despachador cada vez que actualice su GUI.

Aquí hay un par de sugerencias para hacer esto más fácil:

  1. Trate de sus operaciones por lotes GUI. Además de requerir menos código (a través de menos llamadas de invocación), obtendrá un mejor rendimiento. Cada llamada Dispatcher.Invoke conlleva una gran cantidad de gastos generales, ya que publica un mensaje en la cola de mensajes del distribuidor que debe procesarse.

  2. Considere usar Dispatcher.BeginInvoke para evitar el bloqueo, a menos que realmente necesite esperar.

  3. Si puede usar la Biblioteca de tareas paralelas desde .NET 4 (o el backport a 3.5sp1 en el Rx Framework), es posible que desee considerar la posibilidad de modificar esto para usar Task instances synchronized to the GUI thread. Al crear TaskScheduler utilizando FromCurrentSynchronizationContext, puede programar las tareas para que se ejecuten en la GUI más fácilmente que las llamadas de Dispatcher Invoke. Esto también puede darle cierto control sobre el procesamiento por lotes, ya que puede programarlos y bloquear/esperar según sea necesario, muy fácilmente.

2

Se podría utilizar algo como PostSharp o tratar de condensar sus actualizaciones de la interfaz de usuario a un único método llama cuando se invoca una vez y hace un montón. O incluso un patrón como este (es Winforms pero la idea es la misma):

private void UpdateToolStripItemText(ToolStripItem toolStripItem, string text) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new UpdateToolStripItemTextDelegate(UpdateToolStripItemText), new object[] { toolStripItem, text }); 
    } 
    else 
    { 
     if (text != null) 
     { 
      toolStripItem.Text = text; 
     } 
    } 
} 
Cuestiones relacionadas