using System.ComponentModel; namespace System.Windows.Forms { // In WinForms, ContextMenuStrip must be a descendant of ToolStripDropDown. // However in WPF these two classes use different approaches (Popup vs ContextMenu). // That's why we use IPopupWrapper which supplies correct implementation. public partial class ToolStripDropDown : ToolStrip { private IPopupWrapper popup; private bool isOpened; private int closedTicks; internal IPopupWrapper Popup => popup ??= InitPopup(); public new bool Visible => isOpened || (Environment.TickCount - closedTicks) < 300; public event CancelEventHandler Opening; public event EventHandler Opened; public event ToolStripDropDownClosedEventHandler Closed; protected virtual void OnOpening(CancelEventArgs e) => Opening?.Invoke(this, e); protected virtual void OnOpened(EventArgs e) => Opened?.Invoke(this, e); protected virtual void OnClosed(ToolStripDropDownClosedEventArgs e) => Closed?.Invoke(this, e); internal virtual IPopupWrapper CreatePopup() => new PopupWrapper(this); private IPopupWrapper InitPopup() { var popup = CreatePopup(); popup.Opened += (s, e) => { OnOpened(e); isOpened = true; }; popup.Closed += (s, e) => { OnClosed(new ToolStripDropDownClosedEventArgs(ToolStripDropDownCloseReason.ItemClicked)); isOpened = false; closedTicks = Environment.TickCount; }; return popup; } private void OpenPopup() { if (isOpened) { Close(); return; } Popup.FixupDpi(); var args = new CancelEventArgs(); OnOpening(args); if (!args.Cancel) Popup.IsOpen = true; } public void Show(int x, int y) { Popup.Placement = Windows.Controls.Primitives.PlacementMode.Absolute; Popup.HorizontalOffset = x / DpiScale; Popup.VerticalOffset = y / DpiScale; OpenPopup(); } public void Show(System.Drawing.Point screenLocation) => Show(screenLocation.X, screenLocation.Y); public void Show(Control control, int x, int y) { x = (int)(x / control.DpiScale); y = (int)(y / control.DpiScale); Popup.Placement = Windows.Controls.Primitives.PlacementMode.Relative; Popup.PlacementTarget = control.control; Popup.HorizontalOffset = control.control.FlowDirection == FlowDirection.RightToLeft ? control.Width / control.DpiScale - x : x; Popup.VerticalOffset = y; OpenPopup(); } public void Show(Control control, System.Drawing.Point position) => Show(control, position.X, position.Y); internal void Show(Control control) { Popup.Placement = Windows.Controls.Primitives.PlacementMode.Bottom; Popup.PlacementTarget = control.control; OpenPopup(); } public void Close() { // do not close not-yet-opened popup. Case: DataColumnDropDown control if (isOpened) { Popup.IsOpen = false; isOpened = false; } } // TODO? reason param public void Close(ToolStripDropDownCloseReason reason) => Close(); internal override void AddChild(Control child) => Popup.AddChild(child); internal override void RemoveChild(Control child) => Popup.RemoveChild(child); internal override void SetChildIndex(Control child, int index) => Popup.SetChildIndex(child, index); } }