我有一个包含多个子控件的用户控件。我需要用户界面对按键有反应,所以我决定在 MainControl_KeyDown 事件中编写处理代码。然而,当我在应用程序中按下一个键时,这个事件没有触发。
我通过搜索引擎找到了一种解决方案,它依赖于使用 Windows API,但我希望避免使用它,因为这似乎对于.NET框架应该正常支持的功能来说有些过度。
我有一个包含多个子控件的用户控件。我需要用户界面对按键有反应,所以我决定在 MainControl_KeyDown 事件中编写处理代码。然而,当我在应用程序中按下一个键时,这个事件没有触发。
我通过搜索引擎找到了一种解决方案,它依赖于使用 Windows API,但我希望避免使用它,因为这似乎对于.NET框架应该正常支持的功能来说有些过度。
您可以将以下方法添加到您的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);
}
}
yourUC_KeyDown(this, new KeyEventArgs(keyData));
- TaW我知道这个帖子有点老了,但是我遇到了类似的问题,并用不同的方式处理它:
在主窗口中,我将KeyPreview属性更改为true。
我在我的用户控件中注册了主窗口的KeyDown事件处理程序。
this.Parent.KeyDown += new KeyEventHandler(MyControl_KeyDown);
您可以为用户控件中的每个子控件添加一个KeyDown事件处理程序,并在其中触发用户控件的KeyDown事件,如下所示:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
this.OnKeyDown(e);
}
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;
}
}
由于您在 UserControl 中,因此可以简单地重写以下 OnPreviewKeyDown
方法:
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if(e.Key == Key.Escape || e.SystemKey == Key.F10)
{
...
}
}
我有一个技巧。
UcBase
继承自 UserControl
UcSub1
和 UcSub2
也继承自 UcBase
。
UcSuperClass
也继承自 UcBase
。
UcSub1
,UcSub2
在 UcSuperClass
中使用。
我让 UcSub1
和 UcSub2
调用了 ProcessCmdKey
。
代码:
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;
}
}