Как я могу принести вторую (дочернюю) форму в начало z-порядка окон вместе с главной (родительской) формой - PullRequest
0 голосов
/ 28 октября 2018

Как видно из заголовка, у меня есть ситуация, когда я хочу вывести дополнительную форму (FormB, у которой нет значка на панели задач) на передний план (z-порядок), когда моя основная форма (FormA) активирована (имеет фокус).

Например, моя программа работает с двумя формами (FormA и FormB).Затем я открываю блокнот в развернутом виде (просто чтобы покрыть обе формы [FormA и FormB], которые мое приложение содержит на экране).Затем я щелкаю элемент панели задач Windows для своего приложения (которым является FormA) в нижней части экрана, чтобы открыть резервную копию приложения.Когда это происходит, FormB не отображается и остается на заднем плане z-порядка.Я хотел бы, чтобы обе формы были выведены на передний план всех остальных форм.

В конце, при восстановлении FormA, как и в любом обычном приложении, FormB должен быть таким же, как Z-ORDER минус ОДИН.

Пример источника тока

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 голосов
/ 09 ноября 2018

Я закончил тем, что узнал, как сделать это с небольшой пробой и ошибкой.В надежде, что это поможет кому-то другому в будущем, я хотел опубликовать свои выводы здесь.

Поскольку это не поддерживается напрямую классом .NET Form, вам нужно использовать API SetWindowPos.Чтобы это произошло, нужно сделать четыре вещи.Весь приведенный ниже источник может быть добавлен к источнику вашей FORM (FormA).

Как показано ниже, Использование (# 4) показывает пример, который я использовал, используя пункты меню панели инструментов (Файл, Редактировать и т. Д.)в верхней части моей основной формы (FormA).Тогда вторая форма, которая является моей формой журнала (FormB), считается вторичной формой.Это можно сделать с несколькими формами (более 2, как показано в моем примере).

Примечание. Для всех пунктов меню панели инструментов CheckOnClick установлено в значение ИСТИНА.Таким образом, каждый раз, когда вы выбираете пункты меню, они включаются и выключаются.

  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
    
...