文章目錄
-
- 初識
- 走近
- 接觸
-
- 使用Dispatcher
-
- 同步使用Dispatcher
- 異步BeginInvoke
- 參考
初識
所有 WPF 應用程式啟動時都會加載兩個重要的線程:
- 一個用于呈現使用者界面,另一個用于管理使用者界面。
- 呈現線程是一個在背景運作的隐藏線程,是以您通常面對的唯一線程 就是 UI 線程。
- WPF 要求将其大多數對象與 UI 線程進行關聯。這稱之為線程關聯,意味着要使用一個 WPF 對象,隻能在建立它的線程上使用。在其他線程上使用它會導緻引發運作時異常。
-
UI 線程的作用是用于接收輸入、處理事件、繪制螢幕以及運作應用程式代碼。
在 WPF 中絕大部分控件都繼承自 DispatcherObject,甚至包括 Application。這些繼承自 DispatcherObject 的對象具有線程關聯特征,也就意味着隻有建立這些對象執行個體,且包含了 Dispatcher 的線程(通常指預設 UI 線程)才能直接對其進行更新操作。
走近
DispatcherObject 類有兩個主要職責:
- 提供對對象所關聯的目前 Dispatcher 的通路權限
- 提供方法以檢查 (CheckAccess) 和驗證 (VerifyAccess) 某個線程是否有權通路對象(派生于 DispatcherObject)。CheckAccess 與 VerifyAccess 的差別在于 CheckAccess 傳回一個布爾值,表示目前線程是否有可以使用的對象,而 VerifyAccess 則線上程無權通路對象的情況下引發異常。
接觸
-
在 WPF 中,DispatcherObject 隻能通過與它關聯的 Dispatcher 進行通路。 例如,背景線程不能更新由 UI 線程建立的 Label的内容。
那麼如何更新UI線程建立的對象資訊呢?
Dispatcher提供了兩個方法,Invoke和BeginInvoke,這兩個方法還有多個不同參數的重載。
其中Invoke内部還是調用了BeginInvoke,一個典型的BeginInvoke參數如下:
-
Invoke 是同步操作,而 BeginInvoke 是異步操作。
該這兩個操作将按指定的 DispatcherPriority 添加到 Dispatcher 的隊列中。
- DispatcherPriority定義了很多優先級,可以分為前台優先級和背景優先級,其中前台包括 Loaded-Send,背景包括Background-Input。剩下的幾個優先級除了Invalid和Inactive都屬于空閑優先級。這個前台優先級和背景優先級的分界線是以Input來區分的,這裡的Input指的是鍵盤輸入和滑鼠移動、點選等等。
使用Dispatcher
同步使用Dispatcher
private void ModifyUI()
{
// 模拟一些工作正在進行
Thread.Sleep(TimeSpan.FromSeconds(2));
//xaml代碼未列出,lblHello出自 <Label x:Name="lblHello"/>
this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate()
{
lblHello.Content = "歡迎你光臨WPF的世界,Dispatche 同步方法 !!";
});
}
異步BeginInvoke
private void btnAppBeginInvoke_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(2));
this.lblHello.Content = "歡迎你光臨WPF的世界,Dispatche 異步方法!!"+ DateTime.Now.ToString();
}));
}).Start();
}
參考
WPF線程詳解之(一)——Dispatcher詳解