Search code examples
c#winformsfocusbringtofront

Focus a form without bringing it in front of the others


When using the Focus() method, the targeted form acquire focus but is also brought in front of the other forms.

Is there a way to avoid this z-order modification ?

Here is a short example :

class MyForm : Form
{
    static void Main(string[] args)
    {
        MyForm f1 = new MyForm()
        {
            Text = "f1"
        };
        f1.Show();

        MyForm f2 = new MyForm()
        {
            Text = "f2"
        };
        f2.Show();

        Button b1 = new Button();
        b1.Click += (sender, e) => f2.Focus();
        f1.Controls.Add(b1);

        Button b2 = new Button();
        b2.Click += (sender, e) => f1.Focus();
        f2.Controls.Add(b2);

        Application.Run(f1);
    }
}

When clicking the button in f1, f2 will gain focus but will also come in front of f1 (which is the thing I'd like to avoid).


Solution

  • Not really sure it's the best way to do it, but I ended up using the owner property :

    class MyForm : Form
    {
        public const int WM_NCLBUTTONDOWN = 0x00A1;
    
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_NCLBUTTONDOWN:
                    TakeFocus();
                    base.WndProc(ref m);
                    break;
    
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
    
        private void TakeFocus()
        {
            if (Owner == null && OwnedForms.Length > 0)
            {
                Form tmp = OwnedForms[0];
                tmp.Owner = null;
                Owner = tmp;
            }
            BringToFront();
        }
    
        static void Main(string[] args)
        {
            MyForm f1 = new MyForm()
            {
                Text = "f1",
            };
            f1.Show();
    
            MyForm f2 = new MyForm()
            {
                Text = "f2",
            };
            f2.Owner = f1;
            f2.Show();
    
            Button b1 = new Button();
            b1.Click += (sender, e) =>
            {
                f1.TakeFocus();
            };
            f1.Controls.Add(b1);
    
            Button b2 = new Button();
            b2.Click += (sender, e) =>
            {
                f2.TakeFocus();
            };
            f2.Controls.Add(b2);
    
            Application.Run(f1);
        }
    }
    

    In this example, a window gain focus without going in front of the other window when clicking on it's client area. If you click on the non-client area (titlebar and borders) or the button the form gain focus and is brought in front.