From fcbe456cb98dcd37f313090892901a16b18cc709 Mon Sep 17 00:00:00 2001 From: Simon Haines Date: Fri, 29 Oct 2021 16:29:25 +1100 Subject: [PATCH] Filter pointer pressed events from disabled sub-menu items Pointer clicks on disabled and non-interactive items in sub-menus are bubbled up to the sub-menu's parent, causing the sub-menu popup to be closed when it is expected to remain open. This scenario is identified and filtered out by searching for a popup in the logical tree between the source and the handler. Fixes #6412. --- .../Platform/DefaultMenuInteractionHandler.cs | 6 +++++- .../DefaultMenuInteractionHandlerTests.cs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index e361e7b736a..5f82e28722d 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Interactivity; @@ -376,7 +377,10 @@ protected internal virtual void PointerPressed(object sender, PointerPressedEven { if (item.IsSubMenuOpen) { - if (item.IsTopLevel) + // PointerPressed events may bubble from disabled items in sub-menus. In this case, + // keep the sub-menu open. + var popup = (e.Source as ILogical)?.FindLogicalAncestorOfType(); + if (item.IsTopLevel && popup == null) { CloseMenu(item); } diff --git a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs index 1a11091b81e..9eedd177161 100644 --- a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Controls.Platform; +using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.VisualTree; @@ -540,6 +541,22 @@ public void PointerPressed_On_Item_With_SubMenu_Causes_Opens_Submenu() Mock.Get(item).Verify(x => x.MoveSelection(NavigationDirection.First, true), Times.Never); Assert.True(e.Handled); } + + [Fact] + public void PointerPressed_On_Disabled_Item_Doesnt_Close_SubMenu() + { + var target = new DefaultMenuInteractionHandler(false); + var menu = Mock.Of(); + var parentItem = Mock.Of(x => x.IsTopLevel == true && x.HasSubMenu == true && x.IsSubMenuOpen == true && x.Parent == menu); + var popup = new Popup(); + var e = CreatePressed(popup); + + ((ISetLogicalParent)popup).SetParent(parentItem); + target.PointerPressed(parentItem, e); + + Mock.Get(parentItem).Verify(x => x.Close(), Times.Never); + Assert.True(e.Handled); + } } public class ContextMenu