| File: System\Windows\Forms\MDI\MDIControlStrip.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// 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; namespace System.Windows.Forms; /// <summary> /// This is the toolstrip used for merging the [:)] [_][#][X] buttons onto an /// mdi parent when an MDI child is maximized. /// </summary> internal partial class MdiControlStrip : MenuStrip { private readonly ToolStripMenuItem _system; private readonly ToolStripMenuItem _close; private readonly ToolStripMenuItem _minimize; private readonly ToolStripMenuItem _restore; private IWin32Window _target; /// <summary> /// <paramref name="target"/> is ideally the MDI Child to send the system commands to. /// Although there's nothing MDI child specific to it- it could be a top level window. /// </summary> public MdiControlStrip(IWin32Window target) { HMENU hMenu = PInvoke.GetSystemMenu(GetSafeHandle(target), bRevert: false); _target = target; // The menu item itself takes care of enabledness and sending WM_SYSCOMMAND messages to the target. _minimize = new ControlBoxMenuItem(hMenu, PInvoke.SC_MINIMIZE, target); _close = new ControlBoxMenuItem(hMenu, PInvoke.SC_CLOSE, target); _restore = new ControlBoxMenuItem(hMenu, PInvoke.SC_RESTORE, target); // The dropDown of the system menu is the one that talks to native. _system = new SystemMenuItem(); // However in the event that the target handle changes we have to push the new handle into everyone. if (target is Control controlTarget) { controlTarget.HandleCreated += OnTargetWindowHandleRecreated; controlTarget.Disposed += OnTargetWindowDisposed; } // add in opposite order to how you want it merged Items.AddRange(_minimize, _restore, _close, _system); SuspendLayout(); foreach (ToolStripItem item in Items) { item.DisplayStyle = ToolStripItemDisplayStyle.Image; item.MergeIndex = 0; item.MergeAction = MergeAction.Insert; item.Overflow = ToolStripItemOverflow.Never; item.Alignment = ToolStripItemAlignment.Right; item.Padding = Padding.Empty; // image is not scaled well on high dpi devices. Setting property to fit to size. item.ImageScaling = ToolStripItemImageScaling.SizeToFit; } // set up the system menu _system.Image = GetTargetWindowIcon(); _system.Visible = GetTargetWindowIconVisibility(); _system.Alignment = ToolStripItemAlignment.Left; _system.DropDownOpening += OnSystemMenuDropDownOpening; _system.ImageScaling = ToolStripItemImageScaling.None; _system.DoubleClickEnabled = true; _system.DoubleClick += OnSystemMenuDoubleClick; _system.Padding = Padding.Empty; _system.ShortcutKeys = Keys.Alt | Keys.OemMinus; ResumeLayout(false); } public ToolStripMenuItem Close => _close; internal MenuStrip? MergedMenu { get; set; } private Bitmap GetTargetWindowIcon() { HICON hIcon = (HICON)PInvokeCore.SendMessage(GetSafeHandle(_target), PInvokeCore.WM_GETICON, (WPARAM)PInvoke.ICON_SMALL); Icon icon = !hIcon.IsNull ? Icon.FromHandle(hIcon) : Form.DefaultIcon; using Icon smallIcon = new(icon, SystemInformation.SmallIconSize); return smallIcon.ToBitmap(); } private bool GetTargetWindowIconVisibility() => _target is not Form formTarget || formTarget.ShowIcon; public void updateIcon() { _system.Image = GetTargetWindowIcon(); _system.Visible = GetTargetWindowIconVisibility(); } protected internal override void OnItemAdded(ToolStripItemEventArgs e) { base.OnItemAdded(e); Debug.Assert(Items.Count <= 4, "Too many items in the MDIControlStrip. How did we get into this situation?"); } private void OnTargetWindowDisposed(object? sender, EventArgs e) { UnhookTarget(); _target = null!; } private void OnTargetWindowHandleRecreated(object? sender, EventArgs e) { // in the case that the handle for the form is recreated we need to set // up the handles to point to the new window handle for the form. _system.SetNativeTargetWindow(_target); _minimize.SetNativeTargetWindow(_target); _close.SetNativeTargetWindow(_target); _restore.SetNativeTargetWindow(_target); HMENU hmenu = PInvoke.GetSystemMenu(GetSafeHandle(_target), bRevert: false); _system.SetNativeTargetMenu(hmenu); _minimize.SetNativeTargetMenu(hmenu); _close.SetNativeTargetMenu(hmenu); _restore.SetNativeTargetMenu(hmenu); // clear off the System DropDown. if (_system.HasDropDownItems) { // next time we need one we'll just fetch it fresh. _system.DropDown.Items.Clear(); _system.DropDown.Dispose(); } _system.Image = GetTargetWindowIcon(); _system.Visible = GetTargetWindowIconVisibility(); } private void OnSystemMenuDropDownOpening(object? sender, EventArgs e) { if (!_system.HasDropDownItems && (_target is not null)) { _system.DropDown = ToolStripDropDownMenu.FromHMenu(PInvoke.GetSystemMenu(GetSafeHandle(_target), bRevert: false), _target); } else if (MergedMenu is null) { _system.DropDown.Dispose(); } } private void OnSystemMenuDoubleClick(object? sender, EventArgs e) { Close.PerformClick(); } protected override void Dispose(bool disposing) { if (disposing) { UnhookTarget(); _target = null!; } base.Dispose(disposing); } private void UnhookTarget() { if (_target is not null) { if (_target is Control controlTarget) { controlTarget.HandleCreated -= OnTargetWindowHandleRecreated; controlTarget.Disposed -= OnTargetWindowDisposed; } _target = null!; } } }