From 765a2b6004bdf875ee7a8654ab9f4fe418a63ed5 Mon Sep 17 00:00:00 2001 From: David Oliver Date: Thu, 6 May 2021 05:49:55 -0400 Subject: [PATCH] fix(popup): Put Popup in Parent hierarchy of its Child content. Set Popup as Parent of PopupPanel. This emulates UWP behavior that the Popup is a Parent of one of the parents of the Child content, which is relied upon in some cases (eg WCT DataGrid relies upon this for focus management). --- .../Given_Popup.cs | 89 +++++++++++++++++++ .../PopupPages/ReachMainTreePage.xaml | 26 ++++++ .../PopupPages/ReachMainTreePage.xaml.cs | 30 +++++++ .../UI/Xaml/Controls/Popup/PopupPanel.cs | 17 ++-- 4 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/Given_Popup.cs create mode 100644 src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/PopupPages/ReachMainTreePage.xaml create mode 100644 src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/PopupPages/ReachMainTreePage.xaml.cs diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/Given_Popup.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/Given_Popup.cs new file mode 100644 index 000000000000..b4aefb424078 --- /dev/null +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/Given_Popup.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls_Primitives.PopupPages; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +using static Private.Infrastructure.TestServices; + +namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls_Primitives +{ + [TestClass] + [RunsOnUIThread] + public class Given_Popup + { + [TestMethod] + public async Task Check_Can_Reach_Main_Visual_Tree() + { + var page = new ReachMainTreePage(); + WindowHelper.WindowContent = page; + + await WindowHelper.WaitForLoaded(page); + + Assert.IsTrue(CanReach(page.DummyTextBlock, page)); + + try + { + page.TargetPopup.IsOpen = true; + await WindowHelper.WaitForLoaded(page.PopupButton); + + Assert.IsTrue(CanReach(page.PopupButton, page)); + } + finally + { + page.TargetPopup.IsOpen = false; + } + } + +#if __ANDROID__ + [TestMethod] + public async Task Check_Can_Reach_Main_Visual_Tree_Alternate_Mode() + { + var originalConfig = FeatureConfiguration.Popup.UseNativePopup; + FeatureConfiguration.Popup.UseNativePopup = !originalConfig; + try + { + await Check_Can_Reach_Main_Visual_Tree(); + } + finally + { + FeatureConfiguration.Popup.UseNativePopup = originalConfig; + } + } +#endif + + private static bool CanReach(DependencyObject startingElement, DependencyObject targetElement) + { + var currentElement = startingElement; + while (currentElement != null) + { + if (currentElement == targetElement) + { + return true; + } + + // Quoting WCT DataGrid: + // // Walk up the visual tree. Try using the framework element's + // // parent. We do this because Popups behave differently with respect to the visual tree, + // // and it could have a parent even if the VisualTreeHelper doesn't find it. + DependencyObject parent = null; + if (currentElement is FrameworkElement fe) + { + parent = fe.Parent; + } + if (parent == null) + { + parent = VisualTreeHelper.GetParent(currentElement); + } + + currentElement = parent; + } + + // Did not hit targetElement + return false; + } + } +} diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/PopupPages/ReachMainTreePage.xaml b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/PopupPages/ReachMainTreePage.xaml new file mode 100644 index 000000000000..063588b6d92b --- /dev/null +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls_Primitives/PopupPages/ReachMainTreePage.xaml @@ -0,0 +1,26 @@ + + + + + + + + +