Gaurav Sinha
Gaurav Sinha

Reputation: 41

Setting focus when control's top level parent window is the active window?

I am working on a C# project. The issue is that background events like mouse-enter make a background window pop out in focus when it is not the active window. The solution strategy is to add preventive steps before setting this focus.

My attempts include the following strategy:

Prior to the control.Focus() call, I want to implement a condition involving the GetActiveWindow() function to match the control's top level parent's associated window handle. For the latter I am using Control.TopLevelControl(). But, every time I do this, I get null for this property. The reason as per the MSDN reference is that the control is not parented on a form.

Attempted snippet:

if (myControl.TopLevelControl.Handle == GetActiveWindow())
{
     this.myControl.Focus();
}

Background for the code: This code is not owned by me. So, pardon me for being abstract. I will try to be as elaborate as possible. The concerned control is a private member custom layout panel that inherits from System.Windows.Forms.Panel where the DoubleBuffered property is set to true. This control has been added to a internal partial class that inherits from UserControl (Windows Forms). The latter control has been added via a private member SplitContainer (Windows Forms) on a public partial class (inherits from User Control too).

In the constructor of the user control for this layout panel, the even is added as:

myLayoutPanel.MouseEnter += this.myLayoutPanel_MouseEnter;

The event without my change looks like:

private void myLayoutPanel_MouseEnter(object sender, EventArgs e)
    {
        myLayoutPanel.SuspendLayout();
        myLayoutPanel.Focus();
        myLayoutPanel.ResumeLayout(false);
    }

Also, I manually watched on the handles for the control's parent hierarchy and was never able to get a match to the active window handle. Intuitively, I feel the GetActiveWindow() uses interoperability to delve into the unmanaged code to get the handle while the top level property stays in the managed zone and thus has its limits. I might be wrong though.

Does anyone have any thoughts on this?

Upvotes: 3

Views: 954

Answers (1)

TcKs
TcKs

Reputation: 26632

There are two levels of "focus". One is "focus" of Control inside form. And one is "focus" of Form inside whole composition of windows on desktop.

The Control use these members:

The Form use these members:

If you sets focus to control inside the form (via Focus()), the focus is scoped only to the form, and form state is not changed. If you want also sets focus to form, you need activate (via Activate()) the form.

This minimal code to reproduce this behaviour is:

public class MyControl : FlowLayoutPanel {
    private TextBox textBox1;
    private TextBox textBox2;

    public MyControl() {
        this.textBox1 = new TextBox();
        this.Controls.Add(this.textBox1);

        this.textBox2 = new TextBox();
        this.Controls.Add(this.textBox2);

        this.BackColor = Color.Blue; // not required

        this.MouseEnter += this.MyControl_MouseEnter;
    }

    private void MyControl_MouseEnter(object sender, EventArgs e) {
        this.textBox1?.Focus(); // sets focus to the control

        var parentForm = this.FindForm();
        parentForm?.Activate(); // activates the form
    }
}

Upvotes: 3

Related Questions