2011-06-21 10 views
5

Estoy cambiando un proyecto de winforms a WPF. Cuando mi código se basaba en WinForms, utilicé (this.InvokeRequired) para verificar si el hilo tiene acceso. Ahora uso el siguiente código basado en mi Mainform:Problema con el acceso a la IU desde el trabajador de fondo

// this is the delegate declaration to Allow Background worker thread to write to Log Output 
    delegate void LogUpdateCallBack(String LogMessage); 

    // method to update the Log Window from the Background Thread 
    public void LogUpdate(String LogMessage) 
    { 
     Console.WriteLine("Entering"); 
     if (!Application.Current.Dispatcher.CheckAccess()) 
     { 
      Console.WriteLine("Thread doesn't have UI access"); 
      LogUpdateCallBack callback = new LogUpdateCallBack(LogUpdate); 
      Application.Current.Dispatcher.Invoke(callback, LogMessage); 
     } 
     else 
     { 
      Console.WriteLine("Thread has UI access"); 
      listBox_Output.Items.Add(LogMessage); 
      Console.WriteLine(LogMessage); 
      // listBox_Output.TopIndex = listBox_Output.Items.Count - 1; 
     } 
     Console.WriteLine("Exiting"); 
    } 

El problema que tengo es que el cuadro de lista no se actualiza. No hay errores ni excepciones, intenté actualizar otros controles de UI. El LogMessage está escribiendo en la ventana de Salida, así que estoy perplejo.

Aquí es muestra de salida de la consola:

Entering 
Thread doesn't have UI access 
Entering 
Thread has UI access 
My LogMessage is output here 
Exiting 
Exiting 
Entering 
Thread doesn't have UI access 
Entering 
Thread has UI access 
My LogMessage is output here 
Exiting 
Exiting 

He intentado actualizar otros controles de interfaz de usuario sólo para comprobar si se trata de un problema con mi cuadro de lista, pero sin suerte.

Aparte de cambiar a CheckAccess(), el único otro cambio importante que he hecho en el nuevo código WPF es basar todo el código que se ejecuta en el trabajador de segundo plano en otra clase ... No estoy seguro de si esto podría ser parte del problema?

-

@JonRaynor

me trataron su idea:

Application.Current.Dispatcher.BeginInvoke(new LogUpdateCallBack(LogUpdate), LogMessage) 

Sin embargo, mi cuadro de lista todavía no se actualiza, si la salida me

Console.WriteLine(listBox_Output); 

veo la lista cuadro de matriz creciente:

System.Windows.Controls.ListBox Items.Count:2020 
System.Windows.Controls.ListBox Items.Count:2021 
System.Windows.Controls.ListBox Items.Count:2022 
System.Windows.Controls.ListBox Items.Count:2023 
System.Windows.Controls.ListBox Items.Count:2024 
System.Windows.Controls.ListBox Items.Count:2025 

Pero no hay cambio en el formulario. Esto es muy confuso!

+0

Cualquier enlace de datos en el cuadro de lista ? ¿Funciona un Items.Add ("prueba") del evento Page_Load? –

+0

Sin DataBinding .. Estoy actualizando el ListBox desde otras áreas de mi código sin dificultad. También intenté actualizar otros controles de UI en caso de que se tratara de problemas de Listbox ... sin suerte. – mrbencowell

+0

Una cosa más extraña a tener en cuenta ... es que si imprimo listBox_Output en la consola puedo ver que los elementos se agregan (informa el recuento de elementos), por lo que parece que se están agregando mis artículos, sin embargo, la interfaz de usuario no se está actualizado en absoluto. He intentado listBox_Output.InvalidateVisual(); sin efecto – mrbencowell

Respuesta

1

finalmente resuelto este.

Mi problema era que cuando llamaba al método LogUpdate desde otro hilo Y otra clase, necesitaba pasar una referencia a mi formulario principal que contenía el cuadro de lista en esta clase en lugar de crear una nueva instancia del principal formar en la clase secundaria.

así que en lugar de tener esta declaración en mi clase de secundaria:

public MainWindow MainForm = new MainWindow(); 

que necesitaba para pasar una referencia de la forma en el método de la clase secundaria:

public void Plot(BackgroundWorker worker, MainWindow MainForm) 
2

Acabo de empezar a usar WPF y tuve que volver a aprender de la vieja forma de WinForms. He estado usando BeginInvoke() y este tipo de sintaxis en mis pantallas (formularios) ...

public delegate void WorkCompleted(); 

     /// <summary> 
     /// Marks the end of the progress 
     /// </summary> 
     private void ProgressComplete() 
     { 
      if (!this.Dispatcher.CheckAccess()) 
      { 
       this.Dispatcher.BeginInvoke(new WorkCompleted(ProgressComplete), System.Windows.Threading.DispatcherPriority.Normal, null); 
      } 
      else 
      { 
       this.buttonClose.Visibility = Visibility.Visible; 
       this.progressBarStatus.IsIndeterminate = false; 
      } 
     } 
+0

Gracias por la sugerencia. Probaré este método y veré si llego a algún lado. – mrbencowell

0

En WPF, todos los controles de interfaz de usuario se derivan de DispatcherObject. Eso significa que su control ListBox es, en sí mismo, un objeto capaz de despachar. Intente invocar el Dispatcher en ese objeto en lugar de confiar en el formulario en sí. Sacar el parámetro en su delegado (porque tiene acceso a la variable Mensaje de registro de todos modos) y se vería algo como:

public void LogUpdate(string LogMessage) 
{ 
    Console.WriteLine("Entering"); 
    if (listBox_Output.Dispatcher.CheckAccess()) 
    { 
     listBox_Output.Dispatcher.Invoke(new LogUpdateCallBack(delegate 
     { 
      listBox_Output.Items.Add(LogMessage); 
     })); 
     Console.WriteLine(LogMessage); 
    } 
} 
+0

Gracias por la sugerencia, sin embargo, el problema estaba en mi malentendido de declarar una instancia de MainForm en otra clase, asumí que esto me daría acceso a la forma principal, pero meramente creó una nueva instancia de la misma ... así que cuando actualicé controles que no vi un resultado. – mrbencowell

Cuestiones relacionadas