views:

480

answers:

5

I am aware of the KeyPreview property of a Windows Form, and this allows the Form to receive the key events before they get passed to the focused control.

However, I want the Form to receive the event after it has been to the focused control.

As a test I have placed a TextBox on a Form. Upon typing in the TextBox it should perform it's default behavior, upon pressing certain key commands. Ctrl-S, F1, etc, I want those to bubble through the TextBox up to the Form to be handled at a higher level. These commands are those that the TextBox doesn't do by default.

I do need the events to go through the TextBox first though. The application this functionality is needed in is more complex than this simple example. For example, when the TextBox is the focused control it should perform the default Copy & Paste using Ctrl-C and Ctrl-V. However, when various other controls are focused these commands need to end up at the top-most Form-level to be processed there.

Edit: It seems that input events go from Form to Focused Control and not the other way around like I was expecting. If it went from Focus to Form I probably wouldn't be having the problem I have.

Edit2: Having read (briefly) though this article: http://www.codeproject.com/KB/WPF/BeginWPF3.aspx I am now assuming that the sort of 'bubbling' that I was expecting to just 'be there' is only available in WPF, and not standard C#. I think I'm going to have to re-think the way in which the users interact with my app as opposed to writing swathes of ugly code.

Big points to anyone who can reply on doing WPF-style bubbling in C# without ugly code.

A: 

Check out the link given below.

http://www.vbdotnetforums.com/windows-forms/30257-solved-ctrl-s-combobox.html

Hope this helps.

Regards, Raja

Raja
This uses the KeyPreview property; which I'd rather not do as there are a lot of controls which I'd have to override the KeyPress handler.
Wex
A: 

You have to implement it manually unfortunately - implement the KeyDown event handler in your form, check for the global key combinations and set KeyPressEventArgs.Handled = true for them.

For reference: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keydown.aspx

Grzenio
Form.KeyDown isn't called unless KeyPreview property is true. If I use KeyPreview then Ctrl-C nd Ctrl-V will be captured by the form, handled, and never make it to the TextBox.[Moments later...] Actually; just tried it and setting Handled to true doesn't stop the command reaching the TextBox. SuppressKeyPress does stop it... doesn't solve the problem though.
Wex
A: 

You can implement an event handler for the textbox's KeyPress and/or KeyUp/KeyDown events.

In your event handler of the KeyPress event, if you set the Handled property on the event args to true, then the event will not be passed on to the textbox. If you don't set it to true, it will be.

(Edited to clarify the second paragraph).

Anna Lear
That's fine, but the event doesn't continue to bubble up to be caught by the Form.
Wex
I'm not sure what you're asking for, then. I created a Windows Form app, added a textbox to the form, and added an event handler for TextBox's KeyPress in the Form. The form then is the object that handles the TextBox's KeyPress event. There's no "bubbling" that has to happen.
Anna Lear
Umm, the simplest thing to say is that I want the bubbling to happen. :/
Wex
A: 

To be honest I would avoid putting any of, what sounds like complicated logic, in the UI itself. You should create a controller class to handle this. Inside the controller have a method like HandleKeyPress and hook it onto control in question. Based on the specific control, which you can get from the sender param, you can decide what to do.

James
+1  A: 

You may still use KeyPreview property but check which control is focused, if it is a textbox then do nothing, else if it is another control - say RichTextBox - then handle the pressed keys. To get the currently focused control, you may need to access Win32 API. Example: Created a new Windows forms application, add a text box and a richtext box in the form, set the KeyPreview property of the form to true, add an event handler for the KeyDown event of the form, the textbox, and the richtextbox. Also the following using statement:

using System.Runtime.InteropServices;//for DllImport

then replace the code of the form by the following code:

public partial class Form1 : Form
{
    // Import GetFocus() from user32.dll
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
    internal static extern IntPtr GetFocus();

    protected Control GetFocusControl()
    {
        Control focusControl = null;
        IntPtr focusHandle = GetFocus();
        if (focusHandle != IntPtr.Zero)
            // returns null if handle is not to a .NET control
            focusControl = Control.FromHandle(focusHandle);
        return focusControl;
    } 

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        Control focusedControl = GetFocusControl();
        if (focusedControl != null && !(focusedControl is TextBox) && e.Control && e.KeyCode == Keys.C)//not a textbox and Copy
        {
            MessageBox.Show("@Form");
            e.Handled = true;
        }
    }

    private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
    {
        if(e.Control && e.KeyCode == Keys.C)
            MessageBox.Show("@Control");
    }

    private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.C)
            MessageBox.Show("@Control");
    }
}
Sameh Serag
Best answer so far; I'm going to play with this for a bit and see how it goes. Cheers.
Wex
Seems to be working for my needs. As a side note; Control.FromHandle(focusHandle) seems to return null on ToolStripComboBox and in the fields of a PropertyGrid. There may be others; but that's not a big issue for my app.
Wex