WPF的訊息機制(一)- 讓應用程式動起來
前言
談起“訊息機制”這個詞,我們都會想到Windows的訊息機制,系統將鍵盤滑鼠的行為包裝成一個Windows Message,然後系統主動將這些Windows Message派發給特定的視窗,實際上訊息是被Post到特定視窗所線上程的訊息佇列,應用程式的訊息迴圈再不斷的從訊息隊列當中獲取訊息,然後再派發給特定視窗類的視窗過程來處理,在視窗過程中完成一次使用者互動。
其實,WPF的底層也是基於Win32的訊息系統,那麼對於WPF應用程式來說,它是如何跟Win32的訊息互動,這裡到底存在一個什麼樣的機制?接下來我會通過下面幾篇博文介紹這個訊息機制:
WPF的訊息機制(二)-WPF內部的5個視窗
(1)隱藏訊息視窗:控制代碼984620
(2)處理啟用和關閉的訊息的視窗和系統資源通知視窗
(3)用於使用者互動的可見視窗:控制代碼3474914
(4)用於UI視窗繪製的可見視窗:控制代碼1115704
WPF的訊息機制(三)-WPF輸入事件的來源
WPF的訊息機制(四)-WPF中UI的更新
讓應用程式動起來
談到WPF的訊息,首先應該知道DispactherObject以及Dispatcher在WPF系統中的作用。
WPF大部分的物件都是從DispatcherObject派生的,從這裡派生的物件具有一個明顯的特徵,那就是:修改物件時所在的執行緒,和建立物件時所線上程必須為同一個執行緒,這就是微軟所謂的執行緒親緣性(Thread affinity)的最簡單理解。那麼誰能保證執行緒親緣性呢?那就是Dispacher了。從DispatcherObject派生的型別繼承三個重要的成員:Dispatcher屬性,CheckAccess(), VerifyAccess()方法。其中後面兩個方法就是檢驗執行緒親緣性的。按照WPF的實現,如果你自己定義了個WPF的型別,並且是DispatcherObject的子類,你就必須在public的成員定義的邏輯開始處,呼叫base.Dispatcher.VerifyAccess(),檢驗執行緒親緣性。那麼Dispatcher到底還做了什麼事情呢?
首先,我們看一下一個WPF的Application在啟動之後都走了哪些邏輯:
通過呼叫堆疊可以看出,藍色的部分是啟動了一個執行緒,VisualStudio在Host的程序當中運行當前應用程式;紅色的部分是從Application.Main函式開始執行,經過幾個函式到達Dispatcher.Run(),最後到達Dispather.PushFrameInpl()方法。那麼一個Application在Run之後,為什麼要呼叫Dispatcher.Run()呢,他做了些什麼事情你?如果通過Reflector仔細檢視Application.Run(),你會發現裡面實際起作用的程式碼並不多,最後都是Dispatcher.Run在做事情。那麼一個Application啟動之後,按照以前對Win32的訊息機制的理解,當應用程式啟動後,必須進入訊息迴圈,對於WPF,也是一樣的。那麼WPF應用程式是在什麼地方進入訊息迴圈呢?其實這就是Dispatcher.Run()做的事情。檢視上圖最後一步Dispacther.PushFrameImpl()的程式碼,你會看到有下面的一段程式碼:
很明顯,橙色的部分是一個迴圈,看起來是不是很眼熟,跟Win32程式設計碰到的訊息迴圈是否很像?對了,這就是WPF應用程式進入了訊息迴圈。迴圈呼叫GetMessage方法從當前執行緒的訊息隊列當中不停的獲取訊息,取出一個msg之後,交給TranslateAndDispatchMessage方法Dispatch到不同的視窗過程去處理。這樣以來,任何需要應用程式處理的訊息通過這個過程,被不同的視窗處理了,應用程式就動起來了。
下面的一篇我會介紹WPF當中的Win32視窗,正是這些視窗,處理著來自系統,或者來自應用程式內部的訊息。
敬請期待~