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) KeyDownPreviewKeyDown 回调都已经实现,但都没有被调用。

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 你可以使用上面的方法捕获你想要的快捷键。

使其工作的原因是,FormContainerControl 并且 ContainerControl 调用 ProcessCmdKey 中的 ToolStripManager.ProcessCmdKey 方法,这导致所有的处理快捷方式ToolStripManager.
的非上下文菜单条 有关更多信息,请查看 source code for ContainerControl.ProcessCmdKey.