捕获UserControl中的KeyDown事件

时间:2009-07-20 10:25:30

标签: .net winforms c#-2.0

我有一个带有多个子控件的用户控件。我需要用户界面来响应按键,所以我决定将处理代码放在MainControl_KeyDown事件中。但是,当我在我的应用程序中按下某个键时,此事件不会触发。

我通过搜索引擎找到了一个解决方案,该搜索引擎依赖于Windows API的使用,我希望避免使用它,因为对于.NET框架正确支持的功能而言似乎有些过分。< / p>

7 个答案:

答案 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

UcSub1UcSub2继承自UcBaseUcSuperClass也从UcBase继承。

UcSub1UcSub2UcSuperClass内使用。

我生气UcSub1UcSub2调用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)
    {
        ...
    }
}