Make all forms associated with a program come to t

2019-06-24 14:23发布

问题:

I have two forms in my application MainForm and HexCompare. If I click off of my app to another window then I click back on one of the two forms only one of them comes to the front. How can I make it so if I click either one of the two forms it will bring both to the top of all open forms in the application? Right now I need to select each form individually to get them to the top of my stack of windows (and this can be very annoying due to the fact that HexCompare has ShowInTaskbar set to false

A good example of this working the way I want to is how most Find dialogs work. If the find dialog is clicked it brings the main form to the front if it is hidden by another application, and if the main form is clicked the find dialog will come to the front if it is hidden by another application.

How MainForm is invoked.

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}

How HexCompare is invoked

private void lstCaputres_SelectedIndexChanged(object sender, EventArgs e)
{
    var selectedItem = (Tuple<DateTime, byte[]>)lstCaputres.SelectedItem;
    if (hexCompare == null || hexCompare.IsDisposed)
    {
        hexCompare = new HexCompare(selectedItem.Item2);
        hexCompare.Show();
    }
    else
        hexCompare.ChangeValue(selectedItem.Item2);
}

EDIT:

It seems that HexCompare's value of Parent is Null. If I could somehow set it to MainForm would that solve my issue, and if so how to I set it?

EDIT2:

I have semi-solved it using Tigran's solution but it causes flickering as each form is brought to the front, if there is a better solution I am still interested.

//In MainForm.cs
private void MainForm_Activated(object sender, EventArgs e)
{
    hexCompare.BringToFront();
    this.BringToFront();
}

//in HexCompare.cs
private void HexCompare_Activated(object sender, EventArgs e)
{
    parent.BringToFront();
    this.BringToFront();
}

回答1:

You can use the following API wrapper to bring a form to the front of the z-order without having it steal focus. This function can be called in the Activated event of your main form, just pass it your HexCompare form as the parameter. This is not much different from the other answer but I've never witnessed any flicker as you mention in the comments.

  private const int SW_SHOWNOACTIVATE = 4;
  private const int HWND_TOPMOST = 0;
  private const uint SWP_NOACTIVATE = 0x0010;

  [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
  static extern bool SetWindowPos(
       int hWnd,           // window handle 
       int hWndInsertAfter,    // placement-order handle 
       int X,          // horizontal position 
       int Y,          // vertical position 
       int cx,         // width 
       int cy,         // height 
       uint uFlags);       // window positioning flags 

  [DllImport("user32.dll")]
  static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

  public void ShowInactiveTopmost(Form frm)
  {
     ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
     SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
     frm.Left, frm.Top, frm.Width, frm.Height,
     SWP_NOACTIVATE);
  }


回答2:

To me seems that should be enough to set TopMost=true and call BringToFront() on both forms.

hexCompare = new HexCompare(selectedItem.Item2);
hexCompare.TopMost = true;
hexCompare.Show();
hexCompare.BringToFront();

Something like this.