| File: System\ComponentModel\Design\DesignerActionPanel.EditorPropertyLine.FlyoutDialog.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using System.Windows.Forms; namespace System.ComponentModel.Design; internal sealed partial class DesignerActionPanel { private sealed partial class EditorPropertyLine { internal class FlyoutDialog : Form { private readonly Control _hostedControl; private readonly Control _parentControl; public FlyoutDialog(Control hostedControl, Control parentControl, Color borderColor, Font font) { _hostedControl = hostedControl; _parentControl = parentControl; BackColor = SystemColors.Window; ControlBox = false; Font = font; FormBorderStyle = FormBorderStyle.None; MinimizeBox = false; MaximizeBox = false; ShowInTaskbar = false; StartPosition = FormStartPosition.Manual; Text = string.Empty; SuspendLayout(); try { Controls.Add(hostedControl); int width = Math.Max(_hostedControl.Width, SystemInformation.MinimumWindowSize.Width); int height = Math.Max(_hostedControl.Height, SystemInformation.MinimizedWindowSize.Height); if (!borderColor.IsEmpty) { DockPadding.All = 1; BackColor = borderColor; width += 2; height += 4; } _hostedControl.Dock = DockStyle.Fill; Width = width; Height = height; } finally { ResumeLayout(); } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= (int)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW; cp.Style |= unchecked((int)(WINDOW_STYLE.WS_POPUP | WINDOW_STYLE.WS_BORDER)); cp.ClassStyle |= (int)WNDCLASS_STYLES.CS_SAVEBITS; if (_parentControl is not null) { if (!_parentControl.IsDisposed) { cp.Parent = _parentControl.Handle; } } return cp; } } public virtual void FocusComponent() { if (_hostedControl is not null && Visible) { _hostedControl.Focus(); } } // Lifted directly from PropertyGridView.DropDownHolder. Less destructive than using ShowDialog(). public unsafe void DoModalLoop() { while (Visible) { Application.DoEvents(); PInvoke.MsgWaitForMultipleObjectsEx( 0, null, 250, QUEUE_STATUS_FLAGS.QS_ALLINPUT, MSG_WAIT_FOR_MULTIPLE_OBJECTS_EX_FLAGS.MWMO_INPUTAVAILABLE); } } /// <summary> /// General purpose method, based on Control.Contains()... /// Determines whether a given window (specified using native window handle) is a descendant of this control. /// This catches both contained descendants and 'owned' windows such as modal dialogs. /// Using window handles rather than Control objects allows it to catch un-managed windows as well. /// </summary> private bool OwnsWindow(HWND hWnd) { while (!hWnd.IsNull) { hWnd = (HWND)PInvokeCore.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT); if (hWnd.IsNull) { return false; } if (hWnd == (HWND)Handle) { return true; } } return false; } protected override bool ProcessDialogKey(Keys keyData) { if (keyData is (Keys.Alt | Keys.Down) or (Keys.Alt | Keys.Up) or Keys.F4) { // Any of these keys indicates the selection is accepted Visible = false; return true; } return base.ProcessDialogKey(keyData); } public void ShowDropDown(Control parent) { try { PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, parent.Handle); // Lifted directly from Form.ShowDialog(). HWND hWndCapture = PInvoke.GetCapture(); if (!hWndCapture.IsNull) { PInvokeCore.SendMessage(hWndCapture, PInvokeCore.WM_CANCELMODE); PInvoke.ReleaseCapture(); } Visible = true; // NOTE: Do this AFTER creating handle and setting parent FocusComponent(); DoModalLoop(); } finally { PInvokeCore.SetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_HWNDPARENT, IntPtr.Zero); // sometimes activation goes to LALA land - if our parent control is still around, // remind it to take focus. if (parent is not null && parent.Visible) { parent.Focus(); } } } protected override void WndProc(ref Message m) { if (m.MsgInternal == PInvokeCore.WM_ACTIVATE && Visible && m.WParamInternal.LOWORD == PInvoke.WA_INACTIVE && !OwnsWindow((HWND)m.LParamInternal)) { Visible = false; if (m.LParamInternal == 0) { // We 're switching process, also dismiss the parent. Control? toplevel = _parentControl.TopLevelControl; if (toplevel is ToolStripDropDown dropDown) { // If it's a toolstrip dropdown let it know that we have a specific close reason. dropDown.Close(); } else { toplevel?.Visible = false; } } return; } base.WndProc(ref m); } } } }