如何将第二个(子)表单与主(父)表单一起带到Windows z顺序的前面

时间:2018-10-27 23:16:26

标签: c# winforms z-order

正如标题所示,我遇到一种情况,当我激活主表单(FormA)(具有焦点)时,要将二级表单(没有任务栏图标的FormB)置于前面(z顺序)

例如,我的程序运行两种形式(FormA和FormB)。然后,我打开最大化的记事本(只是要覆盖我的应用程序在屏幕上包含的两种形式[FormA和FormB])。然后,在屏幕底部单击适用于我的应用程序(即FormA)的Windows任务栏项,以备份我的应用程序。发生这种情况时,FormB不会显示,而是留在z顺序的背景中。我希望将这两种形式都放在所有其他形式的前面。

最后,当像任何普通应用程序一样还原FormA时,FormB应该是相同的Z-ORDER减ONE。

当前来源示例

public partial class FormA : Form
{
  public FormA()
  {
    Log FormB = new FormB();
    FormB.Show();

    Log FormB = new FormB();
    FormB.ShowDialog();
  }

  private void FormA_Activated(object sender, EventArgs e)
  {
    if (FormB.Visible)
    {
      FormB.Show();
    }
  }
}

1 个答案:

答案 0 :(得分:0)

最后,我经过反复试验,终于找到了如何做的方法。希望对以后的其他人有所帮助,我想在这里发表我的发现。

.NET Form类不直接支持此功能,因此需要使用SetWindowPos API。要做到这一点,需要做四件事。可以将以下所有来源添加到FORM的来源(FormA)。

如下所示,用法(#4)显示了我在主窗体(FormA)顶部使用工具栏菜单项(文件,编辑等)的示例。然后,第二种形式即我的日志形式(FormB)被视为辅助形式。可以使用多种形式来完成此操作(如我的示例所示,可以使用两种以上形式)。

注意:我的所有工具栏菜单项都将CheckOnClick设置为TRUE。这样,每次选择菜单项时,它们都会被打开和关闭。

  1. 声明枚举

    #region Enums
    public enum SpecialWindowHandles
    {
        /// <summary>
        ///     Places the window at the top of the Z order.
        /// </summary>
        HWND_TOP = 0,
    
        /// <summary>
        ///     Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
        /// </summary>
        HWND_BOTTOM = 1,
    
        /// <summary>
        ///     Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
        /// </summary>
        HWND_TOPMOST = -1,
    
        /// <summary>
        ///     Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.
        /// </summary>
        HWND_NOTOPMOST = -2
    }
    
    [Flags]
    public enum SetWindowPosFlags : uint
    {
        /// <summary>
        ///     If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
        /// </summary>
        SWP_ASYNCWINDOWPOS = 0x4000,
    
        /// <summary>
        ///     Prevents generation of the WM_SYNCPAINT message.
        /// </summary>
        SWP_DEFERERASE = 0x2000,
    
        /// <summary>
        ///     Draws a frame (defined in the window's class description) around the window.
        /// </summary>
        SWP_DRAWFRAME = 0x0020,
    
        /// <summary>
        ///     Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
        /// </summary>
        SWP_FRAMECHANGED = 0x0020,
    
        /// <summary>
        ///     Hides the window.
        /// </summary>
        SWP_HIDEWINDOW = 0x0080,
    
        /// <summary>
        ///     Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
        /// </summary>
        SWP_NOACTIVATE = 0x0010,
    
        /// <summary>
        ///     Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
        /// </summary>
        SWP_NOCOPYBITS = 0x0100,
    
        /// <summary>
        ///     Retains the current position (ignores X and Y parameters).
        /// </summary>
        SWP_NOMOVE = 0x0002,
    
        /// <summary>
        ///     Does not change the owner window's position in the Z order.
        /// </summary>
        SWP_NOOWNERZORDER = 0x0200,
    
        /// <summary>
        ///     Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
        /// </summary>
        SWP_NOREDRAW = 0x0008,
    
        /// <summary>
        ///     Same as the SWP_NOOWNERZORDER flag.
        /// </summary>
        SWP_NOREPOSITION = 0x0200,
    
        /// <summary>
        ///     Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
        /// </summary>
        SWP_NOSENDCHANGING = 0x0400,
    
        /// <summary>
        ///     Retains the current size (ignores the cx and cy parameters).
        /// </summary>
        SWP_NOSIZE = 0x0001,
    
        /// <summary>
        ///     Retains the current Z order (ignores the hWndInsertAfter parameter).
        /// </summary>
        SWP_NOZORDER = 0x0004,
    
        /// <summary>
        ///     Displays the window.
        /// </summary>
        SWP_SHOWWINDOW = 0x0040,
    }
    #endregion
    
  2. 声明API

    #region APIs
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool SetWindowPos(IntPtr hWnd, SpecialWindowHandles hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
    #endregion
    
  3. 创建功能

    #region Functions
    private void BringVisibleWindowsToFront()
    {
        //Get parent form handle
        IntPtr hndParentWindow = this.Handle;
    
        //Bring all childern forms to the front
        foreach (Form frmChild in Application.OpenForms)
        {
            //If form is not this form
            if (frmChild.Handle != this.Handle)
            {
                //If form is visible and not minimized
                if (frmChild.WindowState != FormWindowState.Minimized && frmChild.Visible == true)
                    SetWindowPos(frmChild.Handle, SpecialWindowHandles.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
            }
        }
    
        //Set the parent form to the top most z order
        SetWindowPos(hndParentWindow, SpecialWindowHandles.HWND_TOP, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
    }
    
    private void SetAllFormWindowsAlwaysOnTop(bool active)
    {
        SpecialWindowHandles OnTop = (active ? SpecialWindowHandles.HWND_TOPMOST : SpecialWindowHandles.HWND_NOTOPMOST);
    
        //Get parent form handle
        IntPtr hndParentWindow = this.Handle;
    
        //Bring all childern forms to the front
        foreach (Form frmChild in Application.OpenForms)
        {
            //If form is not this form
            if (frmChild.Handle != this.Handle)
            {
                //If form is visible and not minimized
                if (frmChild.WindowState != FormWindowState.Minimized && frmChild.Visible == true)
                    SetWindowPos(frmChild.Handle, OnTop, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
            }
        }
    
        //Set the parent form to the top most z order
        SetWindowPos(hndParentWindow, OnTop, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE | SetWindowPosFlags.SWP_NOACTIVATE);
    }
    #endregion
    
  4. 用法(工具条菜单项示例)

    #region ToolStripMenuItems events
    //Shows or hides the log form (FormB)
    private void showLogToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (showLogToolStripMenuItem.Checked)
        {
            FormB.ShowLog(true);
            SetAllFormWindowsAlwaysOnTop(alwaysOnTopToolStripMenuItem.Checked);
        }
        else
            FormB.ShowLog(false);
    }
    
    //Sets all the forms (in this case FormA and FormB) to always be on top or not
    private void alwaysOnTopToolStripMenuItem_Click(object sender, EventArgs e)
    {
        SetAllFormWindowsAlwaysOnTop(alwaysOnTopToolStripMenuItem.Checked);
    }
    #endregion