2011-02-16 31 views
20

我不完全清楚應用程序中有多少個調度程序,以及它們與線程的關係或引用方式。根據我的理解,WPF應用程序有2個線程(一個用於輸入,另一個用於UI)和一個調度程序(與UI線程相關聯)。如果我創建另一個線程 - 讓我們稱之爲「工作線程」 - 當我在工作線程上調用Dispatcher.CurrentDispatcher時,我將獲得哪個調度程序?調度程序到WPF中的線程關係

另一種情況: 假設一個包含2個線程的控制檯應用程序 - 主線程和輸入線程。在主線程,我首先創建輸入線程,然後我打電話Application.Run()

Thread thread = new Thread(new ThreadStart(UserInputThreadFunction)); 
thread.Start(); 
Application.Run(); 

將有一個調度員,對不對?在輸入線程上,Dispatcher.CurrentDispatcher是否返回主線程的調度程序?或者,讓主線程的調度程序獲得實例的正確方法是什麼?

難道是在WPF應用程序中有多個調度程序嗎?有沒有什麼情況下,創建另一個調度員是有道理的?

回答

25

WPF應用程序具有2個線程(一個 用於輸入,另一個用於UI)

這種說法並不完全正確。 WPF應用程序只有一個UI線程可處理所有UI交互和用戶輸入。還有一個「隱藏」線程負責渲染,但通常開發人員不會處理它。

分派器/線程關係是一對一的,即一個分派器總是被一個線程分配,並且可以用來分派執行到那個線程。 Dispatcher.CurrentDispatcher返回當前線程的調度程序,也就是說,當您在工作線程上調用Dispatcher.CurrentDispatcher時,您將獲得該工作線程的調度程序。

調度員按需創建,這意味着如果您訪問Dispatcher.CurrentDispatcher並且沒有與當前線程關聯的調度程序,則會創建一個。

這就是說,應用程序中調度程序的數量總是少於或等於應用程序中的線程數。

+0

那麼,是否有運行循環運行的每個線程?由於性能原因,我很難想象這一點。 – j00hi 2011-02-16 11:22:54

+0

調度程序是按需創建的,即當您調用Dispatcher.CurrentDispatcher時,如果調度程序尚不存在,則會創建調度程序。 – 2011-02-16 11:45:38

+0

因此,當我在一個工作線程上調用Dispatcher.CurrentDispatcher(並創建工作線程的調度程序)並且訂閱該工作線程上的事件時,是否必須調用Dispatcher.Run()才能接收這些事件? – j00hi 2011-02-17 22:54:49

3

A dispatcher總是與一個線程關聯,並且一個線程最多可以同時運行一個調度程序。一個線程不需要調度器。

默認情況下,只有一個分派器 - 用於UI。有時候有其他調度員是有道理的,而其他調度員則不行。調度線程需要在Dispatcher.Run()方法中阻塞以處理對調度程序的調用。線程(例如控制檯輸入線程)不能用於處理調用。

9

默認情況下,WPF應用程序只有一個Dispatcher。調度程序是唯一允許您與UI元素進行交互的線程。它抽象了你的實現,所以你只需要擔心在UI線程上,即分派器。

如果您想直接與視覺交互(例如,設置使用txtBkx.Text = "new"文本框中的文字),由一個工作線程,那麼你將不得不切換到UI線程:

Application.Current.Dispatcher.Invoke(
    () => { txtBkx.Text = "new"; }); 

或者,您可以使用SynchronizationContext.Current(而在UI線程上)並使用它在不同線程的UI線程上執行委託。正如你應該注意的那樣,Dispatcher.CurrentDispatcher可能並不總是被設置。

現在你可以在實際上在同一個應用程序中創建不同WPF的窗口,併爲每個窗口單獨的調度員:

Thread thread = new Thread(() => 
{ 
    Window1 w = new Window1(); 
    w.Show(); 

    w.Closed += (sender2, e2) => 
    w.Dispatcher.InvokeShutdown(); 

    System.Windows.Threading.Dispatcher.Run(); 
}); 

thread.SetApartmentState(ApartmentState.STA); 
thread.Start(); 

作爲一個方面說明記得在MVVM,你可以從一個非UI線程更新模型並從非UI線程中引發屬性更改事件,因爲WPF將爲您封送PropertyChanged事件。然而,提升CollectionChanged必須在UI線程上。