.net 在 UserControl 中捕获 KeyDown 事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1152784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Capturing KeyDown events in a UserControl
提问by Mark Withers
I have a user control with several child controls. I need the user interface to react to keypresses, so I decided to put the handling code in a MainControl_KeyDown event. However, when I press a key in my application, this event does not fire.
我有一个带有多个子控件的用户控件。我需要用户界面对按键做出反应,因此我决定将处理代码放在 MainControl_KeyDown 事件中。但是,当我在应用程序中按下某个键时,不会触发此事件。
I have found a solution through a search engine which relies upon use of the Windows API, which I would like to avoid, as it seems like overkill for what should be a function that is properly supported by the .NET framework.
我通过依赖于使用 Windows API 的搜索引擎找到了一个解决方案,我想避免这种情况,因为对于 .NET 框架正确支持的功能来说,这似乎有点矫枉过正。
回答by Masoud
You can add following methodto your usercontrol:
您可以将以下方法添加到您的usercontrol:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData == Keys.Right) || (keyData == Keys.Left) ||
(keyData == Keys.Up) || (keyData == Keys.Down))
{
//Do custom stuff
//true if key was processed by control, false otherwise
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
回答by Skalli
I know this thread is a bit old, but I had a similar problem and handled it in a different way:
In the main-window I changed the KeyPreview attribute to true.
I registered the KeyDown-event handler of the main window in my user control.
我知道这个线程有点旧,但我遇到了类似的问题并以不同的方式处理它:
在主窗口中,我将 KeyPreview 属性更改为 true。我在用户控件中注册了主窗口的 KeyDown 事件处理程序。
this.Parent.KeyDown += new KeyEventHandler(MyControl_KeyDown);
This prevents me from routing the KeyDown event of every child control to my user control.
Of course it's important to remove the event handler when you unload your user control.
这会阻止我将每个子控件的 KeyDown 事件路由到我的用户控件。
当然,卸载用户控件时删除事件处理程序很重要。
I hope this helps people who face a similar problem now.
我希望这可以帮助现在面临类似问题的人。
回答by Patrick McDonald
You could add a KeyDown event handler for every child control in your user control and fire the KeyDown event of your user control in each, like so:
您可以为用户控件中的每个子控件添加一个 KeyDown 事件处理程序,并在每个子控件中触发用户控件的 KeyDown 事件,如下所示:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
this.OnKeyDown(e);
}
回答by emredog
maybe you should handle all the events locally and then fire dummy events to communicate with the main control?
也许您应该在本地处理所有事件,然后触发虚拟事件与主控件进行通信?
or maybe this may be a focus issue; if there are many child controls and only one of them is focused, the other ones would not react the key down action.
或者这可能是一个焦点问题;如果有很多子控件并且只有其中一个是焦点,则其他控件不会响应按键操作。
maybe you could post some code snippets here to be sure.
也许你可以在这里发布一些代码片段来确定。
回答by Samuel
Here is an example that loop throw each control in the form to attach the KeyDown event. It's like the previouly answer in this post but handle more cases:
这是一个循环抛出表单中的每个控件以附加 KeyDown 事件的示例。这就像这篇文章中的先前答案,但处理更多情况:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class UserControlKeyboardProcessor
{
private void Control_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
base.OnKeyDown(e);
}
private void UserControlKeyboardProcessor_Disposed(object sender, System.EventArgs e)
{
foreach (System.Windows.Forms.Control control in this.GetAllControls(this)) {
control.KeyDown -= Control_KeyDown;
}
}
private void UserControlKeyboardProcessor_Load(object sender, System.EventArgs e)
{
foreach (System.Windows.Forms.Control control in this.GetAllControls(this)) {
control.KeyDown += Control_KeyDown;
}
}
public Generic.List<System.Windows.Forms.Control> GetAllControls(System.Windows.Forms.Control control)
{
Generic.List<System.Windows.Forms.Control> controls = new Generic.List<System.Windows.Forms.Control>();
foreach (System.Windows.Forms.Control subControl in control.Controls) {
controls.Add(subControl);
controls.AddRange(this.GetAllControls(subControl));
}
return controls;
}
public UserControlKeyboardProcessor()
{
Load += UserControlKeyboardProcessor_Load;
Disposed += UserControlKeyboardProcessor_Disposed;
}
}
回答by Kim Ki Won
I have a trick.
我有一个窍门。
UcBaseinherit from UserControl
UcBase继承自 UserControl
UcSub1and UcSub2inherit from UcBase.
UcSuperClassinherit from UcBasetoo.
UcSub1并UcSub2从UcBase.
UcSuperClass从UcBase太继承。
UcSub1, UcSub2use within UcSuperClass.
UcSub1,UcSub2内使用UcSuperClass。
I mad UcSub1and UcSub2invoke ProcessCmdKey.
我生气UcSub1并UcSub2调用ProcessCmdKey.
Code:
代码:
public class UcBase : UserControl
{
public delegate bool ProcessCmdKeyHandler(Keys keyData);
public ProcessCmdKeyHandler KeyHandler;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
KeyHandler += ProcessKey;
if (Parent != null)
{
var parent = GetParentControl<UcBase>(Parent);
if (parent != null)
{
parent.KeyHandler += ProcessKey;
}
}
}
protected virtual bool ProcessKey(Keys keyData)
{
return false;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if (KeyHandler != null
&& (msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
if (KeyHandler(keyData) == true)
{
return true;
}
}
return base.ProcessCmdKey(ref msg, keyData);
}
private T GetParentControl<T>(Control control)
where T : Control
{
T parentControl = default(T);
var queue = new Queue<Control>();
var targetControlType = typeof(T);
queue.Enqueue(control.Parent);
while (queue.Count > 0)
{
var parent = queue.Dequeue();
if (parent != null)
{
if (parent.GetType().BaseType == targetControlType)
{
parentControl = (T)parent;
break;
}
else
{
queue.Enqueue(parent.Parent);
}
}
else
{
break;
}
}
return parentControl;
}
}
public class UcSub1 : UcBase
{
protected override bool ProcessKey(Keys keyData)
{
// if you process do something, and return true then UcBase.ProcessCmdKey pass by.
return false;
}
}
public class UcSub2 : UcBase
{
protected override bool ProcessKey(Keys keyData)
{
// if you process do something, and return true then UcBase.ProcessCmdKey pass by.
return false;
}
}
public class UcSuperClass : UcBase
{
private UcSub1 _ucSub1;
private UcSub2 _ucSub2;
public UcSuperClass()
{
_ucSub1 = new UcSub1();
_ucSub2 = new UcSub2();
}
protected override bool ProcessKey(Keys keyData)
{
// if you process do something, and return true then UcBase.ProcessCmdKey pass by.
return false;
}
}
回答by Alessandro Muzzi
Since you are in a UserControl, you can simply override OnPreviewKeyDownmethod as shown below:
由于您在 UserControl 中,您可以简单地覆盖OnPreviewKeyDown方法,如下所示:
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if(e.Key == Key.Escape || e.SystemKey == Key.F10)
{
...
}
}

