我有一个带有多个子控件的用户控件。我需要用户界面来响应按键,所以我决定将处理代码放在MainControl_KeyDown事件中。但是,当我在我的应用程序中按下某个键时,此事件不会触发。
我通过搜索引擎找到了一个解决方案,该搜索引擎依赖于Windows API的使用,我希望避免使用它,因为对于.NET框架正确支持的功能而言似乎有些过分。< / p>
答案 0 :(得分:9)
我知道这个帖子有点旧,但我遇到了类似的问题并以不同的方式处理它:
在主窗口中,我将KeyPreview属性更改为true。
我在用户控件中注册了主窗口的KeyDown事件处理程序。
this.Parent.KeyDown += new KeyEventHandler(MyControl_KeyDown);
这可以防止我将每个子控件的KeyDown事件路由到我的用户控件 当然,卸载用户控件时删除事件处理程序非常重要。
我希望这可以帮助那些现在遇到类似问题的人。
答案 1 :(得分:8)
您可以为用户控件中的每个子控件添加一个KeyDown事件处理程序,并在每个控件中触发用户控件的KeyDown事件,如下所示:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
this.OnKeyDown(e);
}
答案 2 :(得分:8)
您可以将following method添加到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);
}
}
答案 3 :(得分:1)
也许您应该在本地处理所有事件,然后触发虚拟事件与主控件进行通信?
或者这可能是焦点问题;如果有许多子控件并且只有其中一个是聚焦的,那么其他控件就不会对按键操作做出反应。
也许你可以在这里发布一些代码片段以确定。
答案 4 :(得分:1)
这是一个循环抛出表单中的每个控件以附加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;
}
}
答案 5 :(得分:0)
我有一个技巧。
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;
}
}
答案 6 :(得分:0)
由于您处于UserControl中,因此可以简单地覆盖OnPreviewKeyDown
方法,如下所示:
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if(e.Key == Key.Escape || e.SystemKey == Key.F10)
{
...
}
}