2012-01-22 4 views
8

Ho una finestra delle opzioni e una finestra che visualizza il colore in base a queste opzioni e ai dati Kinect. Finora tutto è su un thread (per quanto ne so, non ho fatto nessuna discussione).Come si apre una finestra su una nuova discussione?

Ora, sto aggiungendo un'opzione per aprire una finestra del visualizzatore che dovrà essere aggiornata con la latenza più bassa possibile. Tutto ciò comporta sta creando una finestra e mostrarlo:

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

quando gli incendi di questo evento, la finestra di colore ferma visualizzazione dei colori (cioè l'evento che spara 30 volte al secondo sul thread principale si ferma cottura), ma lo spettatore viene visualizzato perfettamente. Voglio che il visualizzatore e la finestra dei colori siano entrambi aggiornati.

Dalla lettura di altre domande, sembra che la soluzione sia creare il visualizzatore su una nuova discussione. Sto incontrando molti problemi con questo, però.

Questo incendi quando si fa clic sul pulsante per aprire il visualizzatore:

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(); 

    } 

Indipendentemente se mi basta chiamare viewer.Show() o Invoke() come sopra, la linea genera un'eccezione: Impossibile utilizzare un oggetto DependencyObject appartenente a un thread diverso rispetto a Freezable padre. Ecco come intendo Invoke(): accede al dispatcher del visualizzatore, che conosce il thread su cui è in esecuzione l'oggetto e può quindi chiamare i metodi da quel thread.

Dovrei provare a mettere questo visualizzatore su una nuova discussione? Il problema è anche una questione di thread? L'utente non interagirà con il visualizzatore.

Qualcuno sa perché questo non funziona? Grazie per l'aiuto.

risposta

15

è necessario chiamare Show() sullo stesso filo che la finestra è stato creato - ecco perché stai ricevendo l'errore. Quindi è anche necessario avviare una nuova istanza di Dispatcher per consentire al runtime di gestire la finestra.

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(); 
} 

Vedi l'/ thread multipli esempio più finestre: http://msdn.microsoft.com/en-us/library/ms741870.aspx

+0

Vedo l'Invoke come garanzia che Show() viene chiamato sul thread del visualizzatore . Anche senza Invoke() attorno al viewer.Show(), ottengo ancora l'eccezione Freezable. –

+0

@ michael.greenwald Poi c'è qualcosa in 'SkeletalViewer.MainWindow()' che sta causando l'eccezione. Ho creato un progetto WPF vuoto che fa esattamente quello che mostro sopra e funziona senza eccezioni. Forse il problema è simile al problema di questa domanda: http://stackoverflow.com/questions/3636761/how-to-debug-this-error-when-none-of-my-code-shows-up-in- the-stack – shf301

+0

E come chiudere quella finestra da 'launchViewerThread'? –

0

Non sono sicuro se questo risolverà il tuo problema, ma puoi provare a creare un proc di thread (per aprire una finestra del visualizzatore) che viene eseguito su un thread diverso e quindi dispatcher.beginInvoke per aggiornare la finestra principale,

Ecco alcune code-

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 questo è possibile aggiornare i comandi principali della finestra senza congelarlo, fatemi sapere se avete domande

+0

Grazie. Perché invii colore al thread dell'interfaccia utente? Non viene invocato alcun metodo chiamato sul thread dell'interfaccia utente, il thread predefinito? –

+0

poiché un thread in background interrotto dal thread principale dell'interfaccia utente non può aggiornare il contenuto di alcun controllo creato nel thread dell'interfaccia utente.Affinché il thread in background possa accedere al controllo sulla finestra principale, il thread in background deve delegare il lavoro al Dispatcher associato al thread dell'interfaccia utente. Ciò si ottiene utilizzando Invoke o BeginInvoke. Invoke è sincrono e BeginInvoke è asincrono. L'operazione viene aggiunta alla coda eventi del Dispatcher in corrispondenza di DispatcherPriority specificato. – DotNetUser

+0

vedi questo link - http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke.aspx – DotNetUser

1

Così stavo correndo in un problema simile in cui è riuscito ad aprire un nuovo thread una nuova finestra. L'eccezione era "impossibile utilizzare un oggetto dipendente che appartiene a un thread diverso".

Il problema era che la finestra utilizzava una risorsa globale (pennello Sfondo). Una volta che ho congelato la risorsa del pennello, la finestra è stata caricata correttamente.