Win Forms UserControl 未检测到按键
Win Forms UserControl not detecting key presses
有很多关于此的问题 (one, two, three, four, five),但我尝试了所有这些问题的修复,但它们要么不起作用,要么不适合我的目的。这是我的基本结构:
User Control
|-Panel
|-Picture Box (several of them, created at runtime, do not exist at design time)
因为我认为它是相关的,面板将其停靠设置为 "fill" 并将调整大小设置为 "grow and shrink",因此它始终覆盖整个用户控件。 PictureBoxes 总是覆盖面板的一部分,但通常不是全部(尽管有可能)。
我专门监听 Ctrl + C
,我需要一种方法,无论哪个 child 有焦点,都可以响应。我想要一种可以侦听任意按键的方法,以便稍后扩展。
链接页面上的一个答案建议为这些按键设置一个全局侦听器,我不想这样做,因为如果它是后台应用程序,我不希望它关闭。另一个建议以顶级形式检测它并将其过滤到我的用户控件。问题是向下的用户控件正在构建为 DLL,我不想强制使用它的应用程序必须实现对 Ctrl + C
的监听,这是它应该处理的事情它自己的。
为什么上面的链接对我不起作用
1) 我没有在我的 UserControl 上将 KeyPreview 属性 设置为 true。该问题的第二个答案建议覆盖 ProcessCmdKey,我这样做了,但无论我尝试什么,都不会调用回调。
2) 这个也建议重写 ProcessCmdKey。正如我所说,它永远不会被调用。
3) 没有让我设置为true的接受按钮。
4) KeyDown
和 PreviewKeyDown
回调都已经实现,但都没有被调用。
5) 还建议使用 ProcessCmdKey。
无论焦点如何,如何在用户控制级别检测按键事件?或者,如果我尝试的上述方法应该有效,我错过了什么设置阻止它工作?
在具有焦点的控件上触发击键事件。您选择的控件不喜欢获得焦点、不显示焦点并且对击键本身没有用处。这确实引出了一个问题,您的应用程序的用户如何可能 知道 Ctrl+C 将要做什么。
我假设 Ctrl+C 应该将 PictureBox 中的图像复制到剪贴板。所以最好的办法是从 PB 派生你自己的 class 并修改它,以便它可以被选择并显示焦点。向您的项目添加一个新的 class 并粘贴如下所示的代码。编译。将其从工具箱顶部拖出,替换用户控件中的 PB。
using System;
using System.Windows.Forms;
using System.Drawing;
class SelectablePictureBox : PictureBox {
public SelectablePictureBox() {
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
if (e.Button == MouseButtons.Left) this.Focus();
base.OnMouseDown(e);
}
protected override void OnEnter(EventArgs e) {
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
if (this.Focused) {
var rc = this.DisplayRectangle;
rc.Inflate(new Size(-2, -2));
ControlPaint.DrawFocusRectangle(e.Graphics, rc);
}
}
}
OP: I am specifically listening for Ctrl + C, and I need a method that can
respond regardless of which child has focus.
如果你想从你的控件中处理像 Ctrl+C 这样的组合键,即使它没有焦点或者它是不可选择,您可以向用户控件添加一个不可见的 MenuStrip
并向其添加一个项目并为其分配快捷方式。然后处理item的点击事件,做你需要做的。
每次用户按下 Ctrl+C 时都会引发点击事件,即使您的控件不包含焦点。
您也可以使用代码:
public UserControl1()
{
InitializeComponent();
var menu = new MenuStrip();
var item = new ToolStripMenuItem();
item.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C;
item.Click += item_Click;
menu.Items.Add(item);
menu.Visible = false;
this.Controls.Add(menu);
}
void item_Click(object sender, EventArgs e)
{
MessageBox.Show("Ctrl + C");
}
备注
你不能在没有焦点的情况下处理按键事件,但是使用 MenuStrip
你可以使用上面的方法捕获你想要的快捷键。
使其工作的原因是,Form
是 ContainerControl
并且 ContainerControl
调用 ProcessCmdKey
中的 ToolStripManager.ProcessCmdKey
方法,这导致所有的处理快捷方式ToolStripManager
.
的非上下文菜单条
有关更多信息,请查看 source code for ContainerControl.ProcessCmdKey
.
有很多关于此的问题 (one, two, three, four, five),但我尝试了所有这些问题的修复,但它们要么不起作用,要么不适合我的目的。这是我的基本结构:
User Control
|-Panel
|-Picture Box (several of them, created at runtime, do not exist at design time)
因为我认为它是相关的,面板将其停靠设置为 "fill" 并将调整大小设置为 "grow and shrink",因此它始终覆盖整个用户控件。 PictureBoxes 总是覆盖面板的一部分,但通常不是全部(尽管有可能)。
我专门监听 Ctrl + C
,我需要一种方法,无论哪个 child 有焦点,都可以响应。我想要一种可以侦听任意按键的方法,以便稍后扩展。
链接页面上的一个答案建议为这些按键设置一个全局侦听器,我不想这样做,因为如果它是后台应用程序,我不希望它关闭。另一个建议以顶级形式检测它并将其过滤到我的用户控件。问题是向下的用户控件正在构建为 DLL,我不想强制使用它的应用程序必须实现对 Ctrl + C
的监听,这是它应该处理的事情它自己的。
为什么上面的链接对我不起作用
1) 我没有在我的 UserControl 上将 KeyPreview 属性 设置为 true。该问题的第二个答案建议覆盖 ProcessCmdKey,我这样做了,但无论我尝试什么,都不会调用回调。
2) 这个也建议重写 ProcessCmdKey。正如我所说,它永远不会被调用。
3) 没有让我设置为true的接受按钮。
4) KeyDown
和 PreviewKeyDown
回调都已经实现,但都没有被调用。
5) 还建议使用 ProcessCmdKey。
无论焦点如何,如何在用户控制级别检测按键事件?或者,如果我尝试的上述方法应该有效,我错过了什么设置阻止它工作?
在具有焦点的控件上触发击键事件。您选择的控件不喜欢获得焦点、不显示焦点并且对击键本身没有用处。这确实引出了一个问题,您的应用程序的用户如何可能 知道 Ctrl+C 将要做什么。
我假设 Ctrl+C 应该将 PictureBox 中的图像复制到剪贴板。所以最好的办法是从 PB 派生你自己的 class 并修改它,以便它可以被选择并显示焦点。向您的项目添加一个新的 class 并粘贴如下所示的代码。编译。将其从工具箱顶部拖出,替换用户控件中的 PB。
using System;
using System.Windows.Forms;
using System.Drawing;
class SelectablePictureBox : PictureBox {
public SelectablePictureBox() {
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
if (e.Button == MouseButtons.Left) this.Focus();
base.OnMouseDown(e);
}
protected override void OnEnter(EventArgs e) {
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
if (this.Focused) {
var rc = this.DisplayRectangle;
rc.Inflate(new Size(-2, -2));
ControlPaint.DrawFocusRectangle(e.Graphics, rc);
}
}
}
OP: I am specifically listening for Ctrl + C, and I need a method that can respond regardless of which child has focus.
如果你想从你的控件中处理像 Ctrl+C 这样的组合键,即使它没有焦点或者它是不可选择,您可以向用户控件添加一个不可见的 MenuStrip
并向其添加一个项目并为其分配快捷方式。然后处理item的点击事件,做你需要做的。
每次用户按下 Ctrl+C 时都会引发点击事件,即使您的控件不包含焦点。
您也可以使用代码:
public UserControl1()
{
InitializeComponent();
var menu = new MenuStrip();
var item = new ToolStripMenuItem();
item.ShortcutKeys = System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C;
item.Click += item_Click;
menu.Items.Add(item);
menu.Visible = false;
this.Controls.Add(menu);
}
void item_Click(object sender, EventArgs e)
{
MessageBox.Show("Ctrl + C");
}
备注
你不能在没有焦点的情况下处理按键事件,但是使用 MenuStrip
你可以使用上面的方法捕获你想要的快捷键。
使其工作的原因是,Form
是 ContainerControl
并且 ContainerControl
调用 ProcessCmdKey
中的 ToolStripManager.ProcessCmdKey
方法,这导致所有的处理快捷方式ToolStripManager
.
的非上下文菜单条
有关更多信息,请查看 source code for ContainerControl.ProcessCmdKey
.