2012-01-22 36 views
8

我有一個選項窗口和一個基於這些選項和Kinect數據顯示顏色的窗口。到目前爲止,一切都在一個線程上(據我所知,我沒有做過任何線程)。如何在新線程上打開窗口?

現在,我添加了一個選項來打開一個查看器窗口,該窗口需要以儘可能低的延遲進行更新。所有這一切都需要是創建一個窗口,並示出它:

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

當這個事件觸發時,顏色窗口停止顯示的顏色(即,觸發該主線程上的30倍的第二事件停止擊發),但觀看者顯示完美。我希望查看器和顏色窗口都被更新。

從閱讀其他問題,這聽起來像解決方案是在一個新的線程創建查看器。不過,我遇到了很多問題。

該火災時,我點擊按鈕,打開瀏覽器:

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

    } 

不管,如果我只是叫viewer.Show()或調用(的),它上面的,行會拋出異常:無法使用屬於與其父級Freezable不同的線程的DependencyObject。下面是我理解Invoke()的方法:它訪問查看器的調度程序,該調度程序知道對象在哪個線程上運行,然後可以從該線程調用方法。

我應該試圖把這個查看器放在一個新的線程上嗎?問題甚至是線程問題嗎?用戶不會與觀衆交互。

任何人都知道爲什麼這不起作用?謝謝您的幫助。

回答

15

你需要調用Show()相同的線程上窗戶被創建 - 這就是爲什麼你會收到錯誤。然後,您還需要啓動一個新的Dispatcher實例,以使運行時管理該窗口。

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

見的多窗口/多線程例子:http://msdn.microsoft.com/en-us/library/ms741870.aspx

+0

我看到Invoke作爲保證Show()在瀏覽器的線程上被調用。即使在viewer.Show()周圍沒有Invoke(),我仍然會得到Freezable異常。 –

+0

@ michael.greenwald然後在'SkeletalViewer.MainWindow()'中有一些東西導致異常。我構建了一個空的WPF項目,它完全符合我上面顯示的內容,並且它毫無例外地運行。也許你的問題類似於這個問題的問題:http://stackoverflow.com/questions/3636761/how-to-debug-this-error-when-none-of-my-code-shows-up-in-堆棧 – shf301

+0

以及如何從'launchViewerThread'關閉那個窗口? –

0

我不確定這是否可以解決您的問題,但是您可以嘗試創建一個在另一個線程上執行的線程處理程序(打開查看器窗口),然後使用dispatcher.beginInvoke更新主窗口,

下面是一些代碼 -

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 
    } 

有了這個,你可以更新主窗口的控制,不會凍結它,讓我知道如果您有任何疑問

+0

謝謝。爲什麼要將顏色派發到UI線程?是不是在UI線程(默認線程)上調用任何調用的方法? –

+0

,因爲從主UI線程分離出的後臺線程無法更新在UI線程上創建的任何控件的內容。爲了後臺線程訪問主窗口上的控制,後臺線程必須將工作委託給與UI線程關聯的分派器。這是通過使用Invoke或BeginInvoke完成的。 Invoke是同步的,Be​​ginInvoke是異步的。該操作將在指定的DispatcherPriority中添加到Dispatcher的事件隊列中。 – DotNetUser

+0

看到這個鏈接 - http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke.aspx – DotNetUser

1

所以我也陷入了類似的問題,即一個新的窗口沒有一個新的線程打開。例外是「不能使用屬於不同線程的依賴對象」。

問題最終導致窗口正在使用全局資源(背景畫筆)。一旦我凍結畫筆資源,窗口加載就好了。