2011-12-02 83 views
2

我想創建一個DispatcherObject的子類來創建我自己的具有消息隊列的線程關聯對象,就像WPF用於UI元素一樣。繼承自DispatcherObject

我有一個測試應用程序運行時沒有崩潰,但DispatcherObject似乎沒有處理它的消息隊列。我剛剛創建了一個新的空白WPF應用程序,並添加以下代碼到MainWindow.xaml.cs

public partial class MainWindow : Window { 
    public MainWindow() { 
     InitializeComponent(); 

     DispatcherWorker worker = null; 
     ManualResetEventSlim latch = new ManualResetEventSlim(false); 

     new Thread(() => { 
      worker = new DispatcherWorker(); 
      latch.Set(); 
     }).Start(); 

     latch.Wait(); 

     // worker.Dispatcher.Thread is stopped by here... why? 
     worker.Dispatcher.BeginInvoke(new Action(() => { 
      // This code never executed 
      worker.DoWork(this); 
     })); 
    } 
} 

public class DispatcherWorker : DispatcherObject { 

    public void DoWork(MainWindow window) { 
     VerifyAccess(); 
     window.Dispatcher.BeginInvoke(new Action(() => window.Background = Brushes.Black)); 
    } 
} 

永遠不會執行該DoWork()方法,如果我把一個斷點只是調用之前BeginInvoke,我看到了Dispatcher的線程停止。爲什麼停止?我是否設置了線程錯誤? (This similar question似乎也有同樣的問題,但接受的答案表示在一個GUI應用程序中運行代碼,這將有一個消息泵,但即使在GUI應用程序中運行,我也遇到同樣的問題。 )

+0

我不知道有關線程或你在做什麼,但是不會有'.Wait()'調用掛起線程直到某些事情完成,但是某些事情永遠不會開始或完成,因爲主UI線程正在等待構造函數完成? – Rachel

+0

@Rachel:'Wait()'調用只會等到'ManualResetEventSlim。Set()'調用,這發生在另一個線程上。當我遍歷代碼時,我可以完全通過構造函數,只是對'worker.Dispatcher.BeginInvoke'的調用沒有效果。 –

回答

3

擁有該Dispatcher需要「泵」是Dispatcher線程的詳細信息。也就是說,它需要被告知處理通過Dispatcher排隊的消息。要做到這一點,您可以使用一個DispatcherFrame

Dispatcher.PushFrame(new DispatcherFrame()); 

您設置的鎖後,這應該會出現。該線程永遠不會退出 - 它只會在該線程的調度程序上抽取消息。如果您希望它具有退出條件,請參閱DispatcherFrameContinue屬性的文檔。

請注意,使用自定義的DispatcherWorker類還是其他內置的WPF類是無關緊要的。如果在該線程上沒有任何信息Dispatcher,則不會處理消息。

+1

做同樣事情的另一種方法是調用Dispatcher.Run()。 – AndrewS

2

我想這是因爲worker.Dispatcher指的是DispatcherObject(在這種情況下,DispatcherWorker)上創建線程,這將是在構造函數中創建的Thread

由於該線程已經啓動並完成工作,當前狀態爲Stopped。你可能不得不再次啓動它運行DoWork()

你可以找到關於這個問題here

0

事實上,你已經創建了一個線程。並且您的DispatcherWorker在創建的線程的範圍內實例化,這使您創建DispatcherWorker的CurrentThread的線程成爲可能。

因此,在BeginInvoke中,DispatcherWorker發生中斷,因爲PostMessage(「user32.dll」)不會從DispatcherWorker中抽取消息。如果您的工作人員在創建的線程範圍之外實例化,那麼所有工作都會順利進行,因爲他的調度員是主線程調度員。

總之,您的工作人員被貶低是因爲在BeginInvoke中沒有可能抽取消息。