diff options
author | Nikita Voronchev <nikita.voronchev@ru.axxonsoft.com> | 2020-01-28 18:30:46 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2020-01-28 18:30:46 +0300 |
commit | c191dba87dee8d8bd25ed3d7247ae47a782cc1c6 (patch) | |
tree | a7bd56efc7ec8363fa12d743bd81f387d7399924 /mcs/class | |
parent | 726a9134c8523f849cb265000c27ed3c5b426d19 (diff) |
[WinForms] Make `ContextMenuStrip` behavior closer to the reference one (#18598)
* [WinForms] Make `ContextMenuStrip` behavior closer to the reference one
* Bump API snapshot submodule
Co-authored-by: monojenkins <jo.shields+jenkins@xamarin.com>
Diffstat (limited to 'mcs/class')
6 files changed, 217 insertions, 56 deletions
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs index 1df14883d09..c95804739f9 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs @@ -35,27 +35,23 @@ namespace System.Windows.Forms [DefaultEvent ("Opening")] public class ContextMenuStrip : ToolStripDropDownMenu { - Control source_control; - internal Control container; + internal Control AssociatedControl; #region Public Construtors public ContextMenuStrip () : base () { - source_control = null; } - public ContextMenuStrip (IContainer container) : base () + public ContextMenuStrip (IContainer container) : this () { - source_control = null; + // TODO: handle `container` argument } #endregion #region Public Properties [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] - public Control SourceControl { - get { return this.source_control; } - } + public Control SourceControl { get; protected set; } #endregion #region Protected Methods @@ -70,11 +66,12 @@ namespace System.Windows.Forms if (visible) XplatUI.SetTopmost (this.Handle, true); } - #endregion - internal void SetSourceControl (Control source_control) + protected override void SetOwnerControl (Control control) { - container = this.source_control = source_control; + base.SetOwnerControl (control); + SourceControl = control; } + #endregion } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs index ecd8c90e51b..d85c52dff6e 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs @@ -2426,7 +2426,7 @@ namespace System.Windows.Forms if (this.context_menu_strip != value) { this.context_menu_strip = value; if (value != null) - value.container = this; + value.AssociatedControl = this; OnContextMenuStripChanged (EventArgs.Empty); } } @@ -5497,22 +5497,21 @@ namespace System.Windows.Forms return; } - // If there isn't a regular context menu, show the Strip version - if (context_menu == null && context_menu_strip != null) { - Point pt; + // If there isn't a regular context menu, show the Strip version + if (context_menu == null && context_menu_strip != null) { + Point pt; - pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); - - if (pt.X == -1 || pt.Y == -1) { - pt.X = (this.Width / 2) + this.Left; - pt.Y = (this.Height /2) + this.Top; - pt = this.PointToScreen (pt); - } - - context_menu_strip.SetSourceControl (this); - context_menu_strip.Show (this, PointToClient (pt)); - return; + pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); + + if (pt.X == -1 || pt.Y == -1) { + pt.X = (this.Width / 2) + this.Left; + pt.Y = (this.Height /2) + this.Top; + pt = this.PointToScreen (pt); } + + context_menu_strip.Show (this, PointToClient (pt)); + return; + } DefWndProc(ref m); } @@ -6499,7 +6498,6 @@ namespace System.Windows.Forms remove { Events.RemoveHandler (ContextMenuStripChangedEvent, value);} } - [EditorBrowsable(EditorBrowsableState.Advanced)] [Browsable(true)] public event ControlEventHandler ControlAdded { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs index 33eb3c50b99..2bf32495378 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs @@ -383,26 +383,36 @@ namespace System.Windows.Forms [EditorBrowsable (EditorBrowsableState.Never)] public new void Show () { - Show (Location, DefaultDropDownDirection); + Show (Location); + } + + public void Show (int x, int y) + { + Show (new Point (x, y)); } public void Show (Point screenLocation) { + SetOwnerControl (null); Show (screenLocation, DefaultDropDownDirection); } - + + public void Show (Control control, int x, int y) + { + Show (control, new Point (x, y)); + } + public void Show (Control control, Point position) { - if (control == null) - throw new ArgumentNullException ("control"); - - XplatUI.SetOwner (Handle, control.Handle); - Show (control.PointToScreen (position), DefaultDropDownDirection); + Show (control, position, DefaultDropDownDirection); } - public void Show (int x, int y) + public void Show (Control control, Point position, ToolStripDropDownDirection direction) { - Show (new Point (x, y), DefaultDropDownDirection); + if (control == null) + throw new ArgumentNullException ("control"); + SetOwnerControl (control); + Show (control.PointToScreen (position), direction); } public void Show (Point position, ToolStripDropDownDirection direction) @@ -522,26 +532,17 @@ namespace System.Windows.Forms this.OnOpened (EventArgs.Empty); } - - public void Show (Control control, int x, int y) - { - if (control == null) - throw new ArgumentNullException ("control"); - Show (control, new Point (x, y)); - } - - public void Show (Control control, Point position, ToolStripDropDownDirection direction) - { - if (control == null) - throw new ArgumentNullException ("control"); - - XplatUI.SetOwner (Handle, control.Handle); - Show (control.PointToScreen (position), direction); - } #endregion #region Protected Methods + + protected virtual void SetOwnerControl (Control ownerControl) + { + var ownerControlHandle = (ownerControl == null) ? IntPtr.Zero : ownerControl.Handle; + XplatUI.SetOwner (Handle, ownerControlHandle); + } + protected override AccessibleObject CreateAccessibilityInstance () { return new ToolStripDropDownAccessibleObject (this); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs index 4df33979088..7a60ac82f29 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs @@ -419,10 +419,8 @@ namespace System.Windows.Forms if (item.Owner == null) return null; - if (item.Owner is ContextMenuStrip) { - Control container = ((ContextMenuStrip)item.Owner).container; - return container == null ? null : container.TopLevelControl; - } + if (item.Owner is ContextMenuStrip ownerContextMenuStrip) + return ownerContextMenuStrip.SourceControl?.TopLevelControl; // MainMenuStrip return item.Owner.TopLevelControl; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources index a4045f284ea..c9eb6898556 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources @@ -26,6 +26,7 @@ System.Windows.Forms/Common.cs System.Windows.Forms/CommonDialogsTest.cs System.Windows.Forms/ContainerControlTest.cs System.Windows.Forms/ContextMenuTest.cs +System.Windows.Forms/ContextMenuStripTest.cs System.Windows.Forms/ControlBindingsCollectionTest.cs System.Windows.Forms/ControlBindingsConverterTest.cs System.Windows.Forms/ControlCollectionTest.cs diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs new file mode 100644 index 00000000000..f5f62d6d330 --- /dev/null +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs @@ -0,0 +1,166 @@ +// +// ContextMenuTestStrip.cs: Test cases for ContextMenuStrip +// +// Author: +// Nikita Voronchev (nikita.voronchev@ru.axxonsoft.com) +// +// (C) 2020 AxxonSoft (https://www.axxonsoft.com/) +// + +using System; +using System.Drawing; +using System.Windows.Forms; +using NUnit.Framework; + +namespace MonoTests.System.Windows.Forms +{ + // TODO: + // -- Tests around `OwnerItem`. + + [TestFixture] + public class ContextMenuStripTest : TestHelper + { + static TestExtendedForm form; + static Label explicitMenuSrcLabel; + static TestExtendedLabel testExtendedLabel; + static ContextMenuStrip contextMenuStrip; + + static readonly Lazy<Control>[] testCaseExplicitMenuSources = new Lazy<Control>[] { + new Lazy<Control>(() => null), + new Lazy<Control>(() => explicitMenuSrcLabel) + }; // Involve `Lazy` to use `TestCaseSource` attribute. + + static readonly Lazy<ITestExtendedControl>[] testCaseAssociatedControls = new Lazy<ITestExtendedControl>[] { + new Lazy<ITestExtendedControl>(() => form), + new Lazy<ITestExtendedControl>(() => testExtendedLabel) + }; // Involve `Lazy` to use `TestCaseSource` attribute. + + [SetUp] + public void SetUp() + { + form = new TestExtendedForm (); + explicitMenuSrcLabel = new Label (); + testExtendedLabel = new TestExtendedLabel (); + contextMenuStrip = new ContextMenuStrip (); + + form.ShowInTaskbar = false; + form.Controls.Add (explicitMenuSrcLabel); + form.Controls.Add (testExtendedLabel); + } + + [TearDown] + public void TearDown() + { + contextMenuStrip.Close (); + form.Controls.Clear (); + + contextMenuStrip.Dispose (); + testExtendedLabel.Dispose (); + explicitMenuSrcLabel.Dispose (); + form.Dispose (); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest01 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (); + Assert.IsNull (contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest02 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (form, Point.Empty); + Assert.AreEqual (form, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest03 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (explicitMenuSrcLabel, Point.Empty); + Assert.AreEqual (explicitMenuSrcLabel, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest04 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (testExtendedLabel, Point.Empty); + Assert.AreEqual (testExtendedLabel, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest05 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (form, Point.Empty); + contextMenuStrip.Close (); + contextMenuStrip.Show (); + Assert.IsNull (contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource("testCaseAssociatedControls")] + public void ContextShowTest (Lazy<ITestExtendedControl> associatedControl) + { + bool menuHasBeenOpened = false; + contextMenuStrip.Opened += (sender, args) => { menuHasBeenOpened = true; }; + + var assCtrl = associatedControl.Value; + assCtrl.ContextMenuStrip = contextMenuStrip; + + Assert.IsFalse (menuHasBeenOpened, "menuHasBeenOpened"); + assCtrl.EmulateWmContextMenu (); + Assert.IsTrue (menuHasBeenOpened, "menuHasBeenOpened"); + Assert.AreEqual (assCtrl, contextMenuStrip.SourceControl, "SourceControl"); + + } + + #region Helpers + + private void AssingOwner (Control explicitMenuSrc) + { + if (explicitMenuSrc != null) + explicitMenuSrc.ContextMenuStrip = contextMenuStrip; + } + + public interface ITestExtendedControl + { + void EmulateWmContextMenu (); + ContextMenuStrip ContextMenuStrip { set; } + } + + class TestExtendedForm : Form, ITestExtendedControl + { + public void EmulateWmContextMenu () + { + var m = TestExtendedControlHelper.MakeWmContextMenu (); + WndProc (ref m); + } + } + + class TestExtendedLabel : Label, ITestExtendedControl + { + public void EmulateWmContextMenu () + { + var m = TestExtendedControlHelper.MakeWmContextMenu (); + WndProc (ref m); + } + } + + static class TestExtendedControlHelper + { + public static Message MakeWmContextMenu () + { + return new Message () { + Msg = (int)Msg.WM_CONTEXTMENU, + LParam = IntPtr.Zero + }; + } + } + + #endregion // end of Helpers + } +} |