From d3ff552515995dac7d16d7e627fdc63d9f358ec6 Mon Sep 17 00:00:00 2001 From: xiaoy312 Date: Thu, 13 Feb 2025 07:23:45 -0500 Subject: [PATCH] fix(droid): add workaround for NavView leaving blank on IsBackButtonVisible update --- .../Given_NavigationView.cs | 116 ++++++++++++++++-- .../Controls/NavigationView/NavigationView.cs | 12 ++ 2 files changed, 121 insertions(+), 7 deletions(-) diff --git a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_NavigationView.cs b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_NavigationView.cs index bddd2428a1ef..dc4f6b121544 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_NavigationView.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Microsoft_UI_Xaml_Controls/Given_NavigationView.cs @@ -1,4 +1,19 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Windows.UI; +using Uno.Extensions; +using Uno.Extensions.Specialized; +using Uno.UI.Extensions; +using Uno.UI.RuntimeTests.Helpers; + +using static Private.Infrastructure.TestServices; +using MUXC = Microsoft/* UWP don't rename */.UI.Xaml.Controls; + #if WINAPPSDK using Uno.UI.Extensions; #elif __IOS__ @@ -7,12 +22,6 @@ using AppKit; #else #endif -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using static Private.Infrastructure.TestServices; -using Windows.UI; -using Microsoft.UI.Xaml.Media; -using Uno.UI.RuntimeTests.Helpers; namespace Uno.UI.RuntimeTests.Tests.Microsoft_UI_Xaml_Controls { @@ -73,5 +82,98 @@ public async Task When_SelectedItem_Set_Before_Load_And_Theme_Changed() #endif } } + + [TestMethod] + public async Task When_IsBackButtonVisible_Toggled() + { + // unoplatform/uno#19516 + // droid-specific: There is a bug where setting IsBackButtonVisible would "lock" the size of all NVIs + // preventing resizing on items expansion/collapse. + + var sut = new MUXC.NavigationView() + { + Height = 500, + IsBackButtonVisible = MUXC.NavigationViewBackButtonVisible.Collapsed, + IsPaneToggleButtonVisible = false, + PaneDisplayMode = NavigationViewPaneDisplayMode.Left, + CompactModeThresholdWidth = 10, + ExpandedModeThresholdWidth = 50, + }; + sut.ItemInvoked += (s, e) => + { + // manual trigger for deepest/inner-most items + if (e.InvokedItemContainer is NavigationViewItem nvi && + nvi.MenuItems.Count == 0) + { + sut.IsBackButtonVisible = NavigationViewBackButtonVisible.Visible; + } + }; + + var nvis = new Dictionary(); + //AddItems(sut.MenuItems, "", count: 4, depth: 1, maxDepth: 2); + AddItems(sut.MenuItems, "", count: 3, depth: 1, maxDepth: 3); + void AddItems(IList target, string prefix, int count, int depth, int maxDepth) + { + for (int i = 0; i < count; i++) + { + var header = prefix + (char)('A' + i); + var item = new NavigationViewItem() { Content = header }; + + if (depth < maxDepth) AddItems(item.MenuItems, header, count, depth + 1, maxDepth); + + target.Add(item); + nvis.Add(header, item); + } + } + + // for debugging + var panel = new StackPanel(); + void AddTestButton(string label, Action action) + { + var button = new Button() { Content = label }; + button.Click += (s, e) => action(); + panel.Children.Add(button); + } + AddTestButton("InvalidateMeasure", () => sut + .EnumerateDescendants().OfType() + .ForEach(x => x.InvalidateMeasure())); + AddTestButton("IsBackButtonVisible toggle", () => sut.IsBackButtonVisible = sut.IsBackButtonVisible == NavigationViewBackButtonVisible.Collapsed + ? NavigationViewBackButtonVisible.Visible + : NavigationViewBackButtonVisible.Collapsed); + panel.Children.Add(sut); + + await UITestHelper.Load(panel, x => x.IsLoaded); + + var initialHeight = nvis["B"].ActualHeight; + + nvis["B"].IsExpanded = true; + await UITestHelper.WaitForIdle(); + var partiallyExpandedHeight = nvis["B"].ActualHeight; + + nvis["BB"].IsExpanded = true; + await UITestHelper.WaitForIdle(); + var fullyExpandedHeight = nvis["B"].ActualHeight; + + // trigger the bug + await Task.Delay(2000); // necessary + sut.IsBackButtonVisible = NavigationViewBackButtonVisible.Visible; + await UITestHelper.WaitForIdle(); + + nvis["BB"].IsExpanded = false; + await UITestHelper.WaitForIdle(); + var partiallyCollapsedHeight = nvis["B"].ActualHeight; + + nvis["B"].IsExpanded = false; + await UITestHelper.WaitForIdle(); + var fullyCollapsedHeight = nvis["B"].ActualHeight; + + // sanity check + Assert.IsTrue(initialHeight < partiallyExpandedHeight, $"Expanding 'B' should increase item 'B' height: {initialHeight} -> {partiallyExpandedHeight}"); + Assert.IsTrue(partiallyExpandedHeight < fullyExpandedHeight, $"Expanding 'BB' should increase item 'B' height: {partiallyExpandedHeight} -> {fullyExpandedHeight}"); + + // verifying fix + Assert.IsTrue(fullyExpandedHeight > partiallyCollapsedHeight, $"Collapsing 'BB' should reduce item 'B' height: {fullyExpandedHeight} -> {partiallyCollapsedHeight}"); + Assert.IsTrue(partiallyCollapsedHeight > fullyCollapsedHeight, $"Collapsing 'B' should reduce item 'B' height: {partiallyCollapsedHeight} -> {fullyCollapsedHeight}"); + } } } diff --git a/src/Uno.UI/Microsoft/UI/Xaml/Controls/NavigationView/NavigationView.cs b/src/Uno.UI/Microsoft/UI/Xaml/Controls/NavigationView/NavigationView.cs index 83cd42ec22c4..6fb057b3e277 100644 --- a/src/Uno.UI/Microsoft/UI/Xaml/Controls/NavigationView/NavigationView.cs +++ b/src/Uno.UI/Microsoft/UI/Xaml/Controls/NavigationView/NavigationView.cs @@ -9,12 +9,14 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Globalization; +using System.Linq; using System.Numerics; using Microsoft/* UWP don't rename */.UI.Xaml.Automation.Peers; using Microsoft/* UWP don't rename */.UI.Xaml.Controls.AnimatedVisuals; using Uno.Disposables; using Uno.Foundation.Logging; using Uno.UI.DataBinding; +using Uno.UI.Extensions; using Uno.UI.Helpers.WinUI; using Windows.ApplicationModel.Core; using Windows.Foundation; @@ -4353,6 +4355,16 @@ private void OnPropertyChanged(DependencyPropertyChangedEventArgs args) { backButton.UpdateLayout(); } + + // workaround for unoplatform/uno#19516 where toggling IsBackButtonVisible would lock the size of all NVIs + if (m_appliedTemplate && IsLoaded) + { + foreach (var ir in this.EnumerateDescendants().OfType()) + { + ir.InvalidateMeasure(); + } + } + UpdatePaneLayout(); }