【问题标题】:Win Forms UserControl not detecting key pressesWin Forms UserControl 未检测到按键
【发布时间】:2016-08-16 17:20:16
【问题描述】:

对此有很多问题(onetwothreefourfive),但我尝试了所有这些问题的修复,但它们要么不起作用,要么不符合我的目的。这是我的基本结构:

User Control
|-Panel
  |-Picture Box (several of them, created at runtime, do not exist at design time)

因为我认为它是相关的,所以面板将其停靠设置为“填充”并将调整大小设置为“增长和缩小”,因此它始终覆盖整个用户控件。图片框总是覆盖面板的一部分,但通常不是全部(尽管有可能)。

我专门监听Ctrl + C,我需要一种不管哪个孩子有焦点都能响应的方法。我想要一种可以监听任意按键的方法,以便稍后进行扩展。

链接页面上的一个答案建议为这些按键创建一个全局侦听器,我不想这样做,因为如果它是后台应用程序,我不希望它关闭。另一个建议在顶级表单中检测它并将其过滤到我的用户控件中。问题是向下的用户控件被构建为一个 DLL,我不想强​​制使用它的应用程序必须实现对Ctrl + C 的侦听,这是它应该自己处理的事情.

为什么上面的链接对我不起作用

1) 我的 UserControl 上没有要设置为 true 的 KeyPreview 属性。该问题的第二个答案建议覆盖 ProcessCmdKey,我这样做了,但无论我尝试什么,都不会调用回调。

2) 这个也建议重写 ProcessCmdKey。正如我所说,它永远不会被调用。

3) 没有让我设置为 true 的接受按钮。

4) KeyDownPreviewKeyDown 回调均已实现,但从未调用过。

5) 还建议使用 ProcessCmdKey。

如何在用户控制级别检测关键事件而不考虑焦点?或者,如果我尝试的上述方法应该可以工作,我错过了哪些设置阻止它工作?

【问题讨论】:

    标签: c# .net winforms user-controls


    【解决方案1】:

    OP:我是专门听Ctrl+C的,我需要一个方法可以 无论哪个孩子有焦点,都做出反应。

    如果您想从您的控件中处理像 Ctrl+C 这样的组合键,即使它没有焦点或不可选择,您也可以添加一个不可见的MenuStrip 到您的用户控件并向其添加项目并为其分配快捷方式。然后处理项目的点击事件并做你需要的。

    即使您的控件不包含焦点,每次用户按下 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你可以使用上述方法捕获你想要的快捷键。

    使它工作的原因是,FormContainerControlContainerControlProcessCmdKey 中调用ToolStripManager.ProcessCmdKey 方法,这会导致处理ToolStripManager 的所有非上下文菜单条的快捷方式。
    如需更多信息,请查看source code 以获取ContainerControl.ProcessCmdKey

    【讨论】:

    • 这似乎是我见过的最简单的方法。如果我最终按照您的方式实施,我会接受。
    • 没问题。你可能会发现它很有用:)
    • 使其工作的原因是,FormContainerControlContainerControlProcessCmdKey 中调用 ToolStripManager.ProcessCmdKey 方法,这会导致处理所有非上下文菜单条的快捷方式ToolStripManager。有关更多信息,请查看Source code 以获取ContainerControl.ProcessCmdKey
    • 如果你想在不控制焦点的情况下捕获快捷键,我相信这是最好的解决方法。
    • 我今天没票了,抱歉。我会尽快解决的。
    【解决方案2】:

    在具有焦点的控件上触发击键事件。您选择了不喜欢获得焦点、不显示焦点并且对击键本身没有用处的控件。这确实引出了一个问题,您的应用程序的用户如何可能知道 Ctrl+C 将要做什么。

    我假设 Ctrl+C 应该将 PictureBox 中的图像复制到剪贴板。所以最好的办法是从 PB 中派生出你自己的类并对其进行修改,以便可以选择它并显示焦点。向您的项目添加一个新类并粘贴如下所示的代码。编译。从工具箱顶部拖动它,替换用户控件中的 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);
            }
        }
    }
    

    【讨论】:

    • 首先让我说用户会知道 Ctrl+C 做什么,我只是不能在这里说(NDA 和所有),但它在上下文中是有意义的。此外,他们不是在复制图像,而是在上面复制文字。我已经可以扫描图像中的文本并知道他们试图选择什么,我已经加载了一个包含该信息的字符串。在 Word 中,您可以突出显示某些文本,并且无论鼠标在窗口上(或窗口外)的哪个位置,Ctrl+C 仍然会复制它。我需要在(最好)不使用全局侦听器时获得该功能,该侦听器会在应用不活动时捕获它。
    • 好吧,这并不重要,只需使用此控件并覆盖 OnKeyDown() 方法即可完成您想做的任何事情。
    猜你喜欢
    • 2019-09-07
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-05
    • 2014-09-15
    相关资源
    最近更新 更多