Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Put focus back on previously focused control on a button click event C# winforms

Form Example

I have made a custom Number Keypad control that I want to place in my winform application. All of the buttons have an OnClick event to send a value to the focused textbox in my form where I have placed my custom control. Like this:

private void btnNum1_Click(object sender, EventArgs e)
{
    if (focusedCtrl != null && focusedCtrl is TextBox)
    {
        focusedCtrl.Focus();
        SendKeys.Send("1");
    }
}

focusedCtrl is supposed to be set on the MouseDown event of the button like this:

private void btnNum1_MouseDown(object sender, EventArgs e)
{
    focusedCtrl = this.ActiveControl;
}

where this.ActiveControl represents the active control on the form.

My problem is that the button always receives the focus before the event detects what the focused control was previously. How can I detect which control had the focus before the button got the focus? Is there another event I should be using? Thanks in advance!

EDIT: Also, I would rather not use the GotFocus event on each textbox in the form to set focusedCtrl since that can be tedious and because I would like to have all the coding of my custom control be in the control itself and not on the form where it is placed. (I will do this, though, if there is no other practical way to do what I am asking)

like image 615
gnarlybracket Avatar asked Mar 23 '23 15:03

gnarlybracket


1 Answers

Your requirement is fairly unwise, you'll want some kind of guarantee that your button isn't going to poke text into inappropriate places. You really do need to have the form co-operate, only it knows what places are appropriate.

But it is not impossible, you can sniff at input events before they are dispatched to the control with the focus. In other words, record which control has the focus before the focusing event is fired. That's possible in Winforms with the IMessageFilter interface.

Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing your existing buttons.

using System;
using System.Windows.Forms;

class CalculatorButton : Button, IMessageFilter {
    public string Digit { get; set; }

    protected override void OnClick(EventArgs e) {
        var box = lastFocused as TextBoxBase;
        if (box != null) {
            box.AppendText(this.Digit);
            box.SelectionStart = box.Text.Length;
            box.Focus();
        }
        base.OnClick(e);
    }
    protected override void OnHandleCreated(EventArgs e) {
        if (!this.DesignMode) Application.AddMessageFilter(this);
        base.OnHandleCreated(e);
    }
    protected override void OnHandleDestroyed(EventArgs e) {
        Application.RemoveMessageFilter(this);
        base.OnHandleDestroyed(e);
    }

    bool IMessageFilter.PreFilterMessage(ref Message m) {
        var focused = this.FindForm().ActiveControl;
        if (focused != null && focused.GetType() != this.GetType()) lastFocused = focused;
        return false;
    }
    private Control lastFocused;
}
like image 199
Hans Passant Avatar answered Apr 06 '23 14:04

Hans Passant