轉(zhuǎn)帖|其它|編輯:郝浩|2010-10-26 14:20:39.000|閱讀 785 次
概述:在WinForm控件上我們可以看到很多關(guān)于鍵盤消息處理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么這些方法是如何被組織的,每一個方法的具體含義又是什么哪?Win32的鍵盤消息又是如何到達控件上的這些方法的,本文將著重闡述這些問題,對.Net WinForm控件的鍵盤消息處理過程進行剖析。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在WinForm控件上我們可以看到很多關(guān)于鍵盤消息處理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么這些方法是如何被組織的,每一個方法的具體含義又是什么哪?Win32的鍵盤消息又是如何到達控件上的這些方法的,本文將著重闡述這些問題,對.Net WinForm控件的鍵盤消息處理過程進行剖析。
1. WinForm消息循環(huán)
大家都知道WinForm也是依賴于底層的消息機制的,通常我們的WinForm應(yīng)用程序會以如下方式啟動:
Application.Run(new Form());
上面的代碼將會在當前線程啟動一個消息循環(huán),并且顯示指定窗體。
反編譯Application類的Run方法,我們可以看到這一點:
public static void Run(Form mainForm)
{
ThreadContext.FromCurrent().RunMessageLoop(-1,new ApplicationContext(mainForm));
}
啟動消息循環(huán)之后,操作系統(tǒng)就會將用戶對于當前應(yīng)用程序的UI輸入轉(zhuǎn)換為Windows消息發(fā)給當前線程進行處理。本文的重點不在于講述Windows消息機制,而在于底層消息到達.Net這一層后,WinForm控件是如何處理的。
2. 消息處理
從上面可以看到通過ThreadContext類型的RunMessageLoop方法,構(gòu)建了消息循環(huán)。那么對于一個特定的Windows消息,ThreadContext又是如何處理的哪?
分析ThreadContext的代碼可以發(fā)現(xiàn)其調(diào)用關(guān)系如下:

在LocalModalMessageLoop方法中我們就可以看到對于Windows消息的處理了:
private bool LocalModalMessageLoop()
{
// ...
if(!PreTranslateMessage(ref msg))
{
// ...
UnsafeNativeMethods.TranslateMessage(ref msg);
UnsafeNativeMethods.DispatchMessage(ref msg);
}
// ...
}
可以發(fā)現(xiàn)對于一個特定的Windows消息,分為兩個階段進行處理:
PreTranslateMessage
DispatchMessage
WinForm控件消息的處理將從這兩個地方開始。
2.1 PreTranslateMessage
PreTranslateMessage提供了一個時機,來決定是否應(yīng)該Dispatch這個消息,如果返回值為False,這個消息才會派發(fā)給WinForm控件。
PreTranslateMessage分為兩個層次,第一優(yōu)先調(diào)用當前應(yīng)用程序的IMessageFilter來進行處理,用戶可以在這一層進行消息預(yù)處理或者消息過濾。如果沒有被過濾掉,調(diào)用當前控件的PreProcessMessage方法進行消息預(yù)處理。
Control類型的PreProcessMessage處理流程如下:

對于WM_KeyDown消息,其預(yù)處理Control類上有三個時機:ProcessCmdKey,IsInputKey以及ProcessDialogKey;對于WM_KeyChar消息,其預(yù)處理有兩個時機:IsInputChar和ProcessDialogChar。
ProcessCmdKey默認用來處理快捷鍵以及菜單快捷鍵,此方法會遞歸調(diào)用父控件。如果返回值為False,繼續(xù)調(diào)用IsInputKey,決定是否引發(fā)KeyDown事件。如果不是InputKey,調(diào)用ProcessDialogKey來檢查該鍵是否為導航鍵,或者進行一些特別的處理,此方法會遞歸調(diào)用父控件的處理。
IsInputChar決定輸入字符是否為普通字符,如果返回值為True會引發(fā)KeyPress事件。返回值為False會調(diào)用ProcessDialogChar,ProcessDialogChar默認用來處理Mnemonic鍵,例如控件的文本為"&OK", 對于Char"O"的處理。
2.2 DispatchMessage
如果PreTranslateMessage沒有過濾掉該Windows消息的話,該消息將會派發(fā)到控件,交由控件的WndProc函數(shù)進行處理。
下圖是控件的處理流程:

消息到達WnProc之后,會交由ProcessKeyMessage,ProcessKeyPreview以及ProcessKeyEventArgs處理。每一個方法都會返回一個Boolean值,表明控件是否已經(jīng)處理了該消息。
ProcessKeyMessage會處理所有由WndProc過來的所有鍵消息,首先會調(diào)用父控件的ProcessKeyPreview函數(shù),如果返回True,表明父控件已經(jīng)處理。否則調(diào)用ProcessKeyEventArgs來觸發(fā)控件的KeyDown,KeyPress,KeyUp事件。
3. 結(jié)語
本文著重講述了WinForm控件對于鍵盤消息的處理,分析了消息預(yù)處理以及處理兩個階段的各個函數(shù)。在進行三方控件的開發(fā)中可以根據(jù)需要重載這些函數(shù),另外也可從其設(shè)計以及實現(xiàn)思路中獲得更多啟發(fā)。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@ke049m.cn
文章轉(zhuǎn)載自:博客轉(zhuǎn)載