2012-01-22 12 views
8

Tengo una ventana de opciones y una ventana que muestra el color en función de estas opciones y los datos de Kinect. Hasta ahora, todo está en un hilo (hasta donde sé, no he hecho ningún enhebrado).¿Cómo abro una ventana en un nuevo hilo?

Ahora, estoy agregando una opción para abrir una ventana de visor que deberá actualizarse con la latencia más baja posible. Todo esto conlleva es la creación de una ventana y que lo muestra:

viewer = new SkeletalViewer.MainWindow(); 
viewer.Show(); 

Cuando los incendios de este evento, el color de la ventana deja de mostrar colores (es decir, el evento que dispara 30 veces por segundo en el hilo principal deja de disparar), pero el espectador se muestra perfectamente. Quiero que el visor y la ventana de color se actualicen.

Al leer otras preguntas, parece que la solución es crear el visor en un nuevo hilo. Sin embargo, estoy teniendo muchos problemas con esto.

Este incendios cuando haga clic en el botón para abrir el visor:

private void launchViewerThread_Click(object sender, RoutedEventArgs e) 
    { 
     Thread viewerThread = new Thread(delegate() 
     { 
      viewer = new SkeletalViewer.MainWindow(); 
      viewer.Dispatcher.Invoke(new Action(delegate() 
       { 
        viewer.Show(); 
       })); 
     }); 

     viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception 
     viewerThread.Start(); 

    } 

Independientemente de si acabo de llamar viewer.Show() o Invoke() como anteriormente, la línea se produce una excepción: No se puede usa un DependencyObject que pertenece a un hilo diferente de su Freezable padre. Así es como entiendo Invoke(): accede al despachador del visor, que sabe en qué subproceso se está ejecutando el objeto, y luego puede llamar a los métodos desde ese subproceso.

¿Debo intentar poner este visor en un nuevo hilo? ¿El problema es incluso una cuestión de hilos? El usuario no interactuará con el espectador.

¿Alguien sabe por qué esto no funciona? Gracias por la ayuda.

Respuesta

15

necesita llamar Show() en el mismo hilo que la ventana se crea en - es por eso que está recibiendo el error. Luego, también debe iniciar una nueva instancia de Dispatcher para obtener el tiempo de ejecución para administrar la ventana.

private void launchViewerThread_Click(object sender, RoutedEventArgs e) 
{ 
    Thread viewerThread = new Thread(delegate() 
    { 
     viewer = new SkeletalViewer.MainWindow(); 
     viewer.Show(); 
     System.Windows.Threading.Dispatcher.Run(); 
    }); 

    viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception 
    viewerThread.Start(); 
} 

Véase el ejemplo Múltiple/Múltiples Hilos de Windows en: http://msdn.microsoft.com/en-us/library/ms741870.aspx

+0

Veo la invocación como garantía de que se llama a Show() en el hilo del visor . Incluso sin Invoke() alrededor del espectador. Show(), todavía obtengo la excepción de Freezable. –

+0

@ michael.greenwald Luego hay algo en 'SkeletalViewer.MainWindow()' que causa la excepción. Construí un proyecto WPF vacío que hace exactamente lo que muestro arriba y se ejecuta sin excepción. Tal vez su problema es similar al problema de esta pregunta: http://stackoverflow.com/questions/3636761/how-to-debug-this-error-when-none-of-my-code-shows-up-in- the-stack – shf301

+0

¿Y cómo cerrar esa ventana de 'launchViewerThread'? –

0

No estoy seguro si esto solucionará su problema pero puede intentar crear un proceso de hilo (para abrir una ventana de visor) que se ejecuta en un hilo diferente y luego tener un dispatcher.beginInvoke para actualizar la ventana principal,

Aquí es un poco de código-

in the constructor register this 
    public MainWindow() 
    { 
     UpdateColorDelegate += UpdateColorMethod; 
    } 

    // delegate and event to update color on mainwindow 
    public delegate void UpdateColorDelegate(string colorname); 
    public event UpdateColorDelegate updateMainWindow; 

    // launches a thread to show viewer 
    private void launchViewerThread_Click(object sender, RoutedEventArgs e) 
    { 
     Thread t = new Thread(this.ThreadProc); 
     t.Start(); 
    } 

    // thread proc 
    public void ThreadProc() 
    { 
     // code for viewer window 
     ... 
     // if you want to access any main window elements then just call DispatchToMainThread method 
     DispatchToUiThread(color); 
    } 

    // 
    private void DispatchToUiThread(string color) 
    { 
     if (updateMainWindow != null) 
     { 
     object[] param = new object[1] { color}; 
     Dispatcher.BeginInvoke(updateMainWindow, param); 
     } 
    } 

    // update the mainwindow control's from this method 
    private void UpdateColorMethod(string colorName) 
    { 
     // change control or do whatever with main window controls 
    } 

con esto se puede actualizar los principales controles de la ventana sin congelarla, hágamelo saber si usted tiene alguna pregunta

+0

Gracias. ¿Por qué envías colores al hilo de la interfaz de usuario? ¿No se invoca ningún método llamado en el subproceso UI, el subproceso predeterminado? –

+0

porque un hilo de fondo que se separa del subproceso principal de la interfaz de usuario no puede actualizar el contenido de ningún control que se haya creado en el subproceso de la interfaz de usuario.Para que el subproceso en segundo plano acceda al control en la ventana principal, el hilo de fondo debe delegar el trabajo al distribuidor asociado con el subproceso de interfaz de usuario. Esto se logra usando Invoke o BeginInvoke. Invoke es sincrónico y BeginInvoke es asincrónico. La operación se agrega a la cola de eventos del Dispatcher en DispatcherPriority especificado. – DotNetUser

+0

consulte este enlace - http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke.aspx – DotNetUser

1

Así que yo estaba corriendo en un problema similar en una nueva ventana no se abrió en un nuevo hilo. La excepción fue "no se puede usar un objeto de dependencia que pertenece a un hilo diferente".

El problema terminó siendo que la ventana usaba un recurso global (Cepillo de fondo). Una vez que congelé el recurso de pincel, la ventana cargó muy bien.

Cuestiones relacionadas