![](/img/trans.png)
[英]Button prevents KeyDown event from triggering even with keypreview = true
[英]KeyDown event is not firing, KeyPreview set to true
我正在構建一個小型Forms應用程序,我剛剛啟動它。 但我有這個問題:如果我將一個控件放到窗體上,KeyDown事件不會觸發。 我知道KeyPreview屬性,並將其設置為true。 但這沒有幫助... :(我也試圖把焦點放在主要形式上,也沒有成功。
有什么想法嗎?
編輯:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyDown += new KeyEventHandler(Form1_KeyDown);
this.KeyPreview = true;
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Left: MessageBox.Show("Left");
break;
case Keys.Right: MessageBox.Show("Right");
break;
}
}
}
我已經評論了我的解決方案,但我也將其作為答案發布,因此很容易找到。
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Left:
// left arrow key pressed
return true;
case Keys.Right:
// right arrow key pressed
return true;
case Keys.Up:
// up arrow key pressed
return true;
case Keys.Down:
// down arrow key pressed
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
如果您使用的是WPF,則可以輕松捕獲所需的事件,因為WPF使用路由事件系統來分派事件。 在winforms中,我推薦以下兩種方式之一:
Application.AddMessageFilter Method
: 定義消息過濾器類:
public class KeyMessageFilter : IMessageFilter
{
private enum KeyMessages
{
WM_KEYFIRST = 0x100,
WM_KEYDOWN = 0x100,
WM_KEYUP = 0x101,
WM_CHAR = 0x102,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105,
WM_SYSCHAR = 0x0106,
}
[DllImport("user32.dll")]
private static extern IntPtr GetParent(IntPtr hwnd);
// We check the events agains this control to only handle
// key event that happend inside this control.
Control _control;
public KeyMessageFilter()
{ }
public KeyMessageFilter(Control c)
{
_control = c;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == (int)KeyMessages.WM_KEYDOWN)
{
if (_control != null)
{
IntPtr hwnd = m.HWnd;
IntPtr handle = _control.Handle;
while (hwnd != IntPtr.Zero && handle != hwnd)
{
hwnd = GetParent(hwnd);
}
if (hwnd == IntPtr.Zero) // Didn't found the window. We are not interested in the event.
return false;
}
Keys key = (Keys)m.WParam;
switch (key)
{
case Keys.Left:
MessageBox.Show("Left");
return true;
case Keys.Right:
MessageBox.Show("Right");
return true;
}
}
return false;
}
}
因此,您有一個類,Windows窗體中的每個消息都通過它。 你可以隨意為活動做任何事情。 如果PreFilterMessage
方法返回true,則表示不應將事件分派給它的respcetive控件。
(請注意, Keys
枚舉中的值幾乎是虛擬鍵代碼的必要條件)
在此之前,您必須將其添加到應用程序的消息過濾器:
public partial class Form1 : Form
{
// We need an instance of the filter class
KeyMessageFilter filter;
public Form1()
{
InitializeComponent();
filter = new KeyMessageFilter(panel1);
// add the filter
Application.AddMessageFilter(filter);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
// remove the filter
Application.RemoveMessageFilter(filter);
}
}
過濾器僅在Form1
的生命周期內處於活動狀態。
注意:這將捕獲任何形式的事件! 如果您希望它僅適用於一個表單,請將表單傳遞給過濾器類,並將其Handle
屬性與PreFilterMessage
m.HWnd
進行比較
這是一種更先進,更復雜(和低級別)的方法。 它需要更多代碼。 我寫了一個HookManager
類,使得這個過程非常簡單。 我要把這個類發布到github並寫一篇關於它的文章。
您觀察到的行為的原因是特殊鍵,如TAB,上/下/左/右箭頭,PAGE UP / DOWN,HOME,END等,通常被通用控件視為“輸入鍵”。
例如,ARROW鍵被TabControl視為“輸入鍵”,因為這些鍵允許您更改選定的TabPage。 多行TextBox存在類似的行為,其中ARROWS鍵允許您移動文本光標。
我認為由於同樣的原因,你所擁有的Rumba Mainframe控件做同樣的事情。 您可以嘗試覆蓋它並更改IsInputKey方法的實現或處理PreviewKeyDown事件並將IsInputKey屬性設置為true。
有關更多詳細信息,請參閱Control.IsInputKey方法和Control.PreviewKeyDown事件的文檔
箭頭鍵是一種由控件自動處理的特殊鍵。 因此,如果您想讓它們引發KeyDown事件,您可以:
1)在表單的每個控件中重寫isInputKey方法
要么
2)處理PreviewKeyDown事件並將IsInputKey屬性設置為true
更多信息可以在這里找到。
我知道WonderCsabo已經解決了他的問題,但是有人給了它一個賞金,因為它有同樣的問題並且沒有選擇答案。 WonderCsabo也請發布您的解決方案作為答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.