Search code examples
winformseventsevent-handlinguser-controlswindows-forms-designer

How do I trigger a form level event when a user control has the focus?


I have a Windows Form C#/.Net project. There is a form with several user controls on it. Each user control is docked so that it takes up the whole form. When a button on one user control is clicked, that user control is hidden and another one appears. This was done by a coworker and is in production and can't be changed (that is, I absolutely can't get rid of the user controls and can't change them unless really necessary). I want a panel (or maybe another user control) on the form that can be brought up on some event (like hitting a certain key combination like CTRL-Q). However, if I put a KeyDown event on the form, it never gets triggered because one of the user controls always has the focus. I could put my new panel on each user control and have KeyDown events on each of them, but I'm not really supposed to change the existing user controls and I don't really want multiple instances of this panel and multiple events. How can I trigger a form level event when one of the user controls has the focus?

Here is how the form, user control, and panels are laid out. The user controls are actually docked to fill the entire form; I staggered them in this illustration so you could see them all.

----------------------------------------------------------------------
| form1                                                              |
|                                                                    |
| ---------------------------------------------------------------    |
| | userControl1                                                |    |
| |                                                             |    |
| |                                                             |    |
| | --------------------------------------------------------    |    |
| | | userControl2                                         |    |    |
| | |                                                      |    |    |
| | |                                                      |    |    |
| | | --------------------------------------------------   |    |    |
| | | | userControl3                                    |  |    |    |
| | | |                                                 |  |    |    |
| | | ---------------------------------------------------  |    |    |
| | |                                                      |    |    |
| | --------------------------------------------------------    |    |
| |                                                             |    |
| ---------------------------------------------------------------    |
|                                                                    |
|                                                                    |
| ------------------------------------------------------------------ |
| | panel or user control on top of everything, visible on demand  | |
| ------------------------------------------------------------------ |
|                                                                    |
----------------------------------------------------------------------

What I want is for this event from form1 to get triggered no matter what user control is active:

    private void form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.Q)
        {
            panel1.Visible = true;
        }
    }

Solution

  • If you want to use the KeyDown or KeyUp events on a form, always make sure that the property KeyPreview on the form is set to TRUE

    This property will then make sure the form gets the keystroke first, before the controls do

    See also this

    EDIT
    Another way is to stop using the KeyDown/KeyUp event for this, and override the ProcessCmdKey on the form, as @Jimi suggested in his comment

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        bool Result = true;
    
        if (keyData == Keys.Control | Keys.Q)
        {
             panel1.Visible = true;
        }
        else
        {
            Result = base.ProcessCmdKey(ref msg, keyData);
        }
    
        return Result;
    }