【问题标题】:Focus a child Control of a User Control when a combination of keys is pressed按下组合键时聚焦用户控件的子控件
【发布时间】:2021-10-24 18:13:47
【问题描述】:

我有一个表单,其中包含一个面板,我在其中放置了一个用户控件。
我希望当按下 Ctrl+F 组合键时,我的 UserControl 的子 TextBox 控件获得焦点。

结构是这样的:

到目前为止,我已经尝试处理 KeyPreviewKeyDown 事件。我可以显示一个 MessegeBox:

但我无法将文本框集中在我的 UserControl 中。
我该如何解决这个问题?

【问题讨论】:

    标签: c# winforms user-controls focus


    【解决方案1】:

    您可能可以实现IMessageFilter 并处理您想要的组合键。
    然后,您必须使用 Application.AddMessageFilter() 添加消息过滤器,并在不再需要时使用 Application.RemoveMessageFilter() 将其删除。

    这里,UserControl 的DesignMode 属性被选中,所以过滤器只在run.time 添加。

    可能,添加一个可以添加/删除/更改键组合的公共属性,以防与其他控件发生冲突。

    GetAncestor()函数用于判断触发Keys组合的Form是否是UserControl这个实例的Parent Form。
    PreFilterMessage()在应用的任意Form生成消息时调用.
    如果您想在任何情况下执行某个操作,即使组合是在另一个打开的表单中生成的(并且可能会弹出前面的父表单),只需删除该检查即可。


    过滤 Control + F
    如前所述,如果您需要更多过滤器,请使用集合来处理这些组合。

    当收到WM_KEYDOWN 时,WParam 包含虚拟密钥代码。虚拟键值相当于Keys 枚举器。
    ModifierKeys 属性包含当前活动的键修饰符(此处仅测试 Control 键,当然您可以添加其他使用的快捷键,例如 CTRL+SHIFT)。

    using System.ComponentModel;
    using System.Runtime.InteropServices;
    
    public partial class SomeUserControl : UserControl, IMessageFilter
    {
        public SomeUserControl() => InitializeComponent();
        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_KEYDOWN) {
                if (GetAncestor(m.HWnd, 2).Equals(ParentForm.Handle)) {
                    if (m.WParam.ToInt32() == (int)Keys.F && ModifierKeys == Keys.Control) {
                        someChildTextBox.Focus();
                    }
                }
            }
            return false;
        }
    
        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);
            if (!DesignMode) Application.AddMessageFilter(this);
        }
    
        protected override void OnHandleDestroyed(EventArgs e) {
            if (!DesignMode) Application.RemoveMessageFilter(this);
            base.OnHandleDestroyed(e);
        }
    
        private const int WM_KEYDOWN = 0x0100;
    
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr GetAncestor(IntPtr hWnd, uint flags);
    }
    

    【讨论】:

    • 感谢您的回答,我试过了,它解决了我的问题。 (实际上,我从您的第一条评论中看不懂(因为我是 C# 新手)并且不知道如何使用)。无论如何,再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    • 2012-12-18
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多