diff --git a/src/Controls/src/Core/FlyoutPage/FlyoutPage.Mapper.cs b/src/Controls/src/Core/FlyoutPage/FlyoutPage.Mapper.cs index 8f74e8987301..03f19806ad8e 100644 --- a/src/Controls/src/Core/FlyoutPage/FlyoutPage.Mapper.cs +++ b/src/Controls/src/Core/FlyoutPage/FlyoutPage.Mapper.cs @@ -12,6 +12,9 @@ public partial class FlyoutPage #if IOS FlyoutViewHandler.Mapper.ReplaceMapping(nameof(PlatformConfiguration.iOSSpecific.Page.PrefersHomeIndicatorAutoHiddenProperty), MapPrefersHomeIndicatorAutoHiddenProperty); FlyoutViewHandler.Mapper.ReplaceMapping(nameof(PlatformConfiguration.iOSSpecific.Page.PrefersStatusBarHiddenProperty), MapPrefersPrefersStatusBarHiddenProperty); +#endif +#if WINDOWS + FlyoutViewHandler.Mapper.ReplaceMapping(nameof(PlatformConfiguration.WindowsSpecific.FlyoutPage.CollapseStyleProperty), MapCollapseStyle); #endif } @@ -31,5 +34,28 @@ internal static void MapPrefersPrefersStatusBarHiddenProperty(IFlyoutViewHandler handler.UpdateValue(nameof(PlatformConfiguration.iOSSpecific.Page.PrefersStatusBarHiddenProperty)); } #endif + +#if WINDOWS + internal static void MapCollapseStyle(IFlyoutViewHandler handler, IFlyoutView view) + { + var flyoutLayoutBehavior = (view as FlyoutPage)?.FlyoutLayoutBehavior; + if (view is BindableObject bindable && handler.PlatformView is Microsoft.Maui.Platform.RootNavigationView navigationView && flyoutLayoutBehavior is FlyoutLayoutBehavior.Popover) + { + var collapseStyle = PlatformConfiguration.WindowsSpecific.FlyoutPage.GetCollapseStyle(bindable); + switch (collapseStyle) + { + case PlatformConfiguration.WindowsSpecific.CollapseStyle.Partial: + navigationView.FlyoutPaneDisplayMode = Microsoft.UI.Xaml.Controls.NavigationViewPaneDisplayMode.LeftCompact; + navigationView.PaneDisplayMode = Microsoft.UI.Xaml.Controls.NavigationViewPaneDisplayMode.LeftCompact; + break; + case PlatformConfiguration.WindowsSpecific.CollapseStyle.Full: + default: + navigationView.FlyoutPaneDisplayMode = null; + navigationView.PaneDisplayMode = Microsoft.UI.Xaml.Controls.NavigationViewPaneDisplayMode.LeftMinimal; + break; + } + } + } +#endif } } diff --git a/src/Controls/src/Core/PlatformConfiguration/WindowsSpecific/FlyoutPage.cs b/src/Controls/src/Core/PlatformConfiguration/WindowsSpecific/FlyoutPage.cs index 0fc4ae52f19a..0b8a8e399852 100644 --- a/src/Controls/src/Core/PlatformConfiguration/WindowsSpecific/FlyoutPage.cs +++ b/src/Controls/src/Core/PlatformConfiguration/WindowsSpecific/FlyoutPage.cs @@ -13,7 +13,15 @@ public static class FlyoutPage /// Bindable property for . public static readonly BindableProperty CollapseStyleProperty = BindableProperty.CreateAttached("CollapseStyle", typeof(CollapseStyle), - typeof(FlyoutPage), CollapseStyle.Full); + typeof(FlyoutPage), CollapseStyle.Full, propertyChanged: OnCollapseStylePropertyChanged); + + static void OnCollapseStylePropertyChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is Microsoft.Maui.Controls.FlyoutPage flyoutPage && flyoutPage.Handler is not null) + { + flyoutPage.Handler.UpdateValue(nameof(CollapseStyleProperty)); + } + } /// public static CollapseStyle GetCollapseStyle(BindableObject element) diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue18200.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue18200.cs new file mode 100644 index 000000000000..14053c9f85a3 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue18200.cs @@ -0,0 +1,79 @@ +using Microsoft.Maui.Controls.PlatformConfiguration; +using Microsoft.Maui.Controls.PlatformConfiguration.WindowsSpecific; + +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, 18200, "Flyout Page SetCollapseStyle doesn't have any change", PlatformAffected.UWP)] +public class Issue18200 : TestFlyoutPage +{ + Button _button; + protected override void Init() + { + this.On().SetCollapseStyle(CollapseStyle.Partial); + + // Set the flyout page properties + FlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover; + + // Create the flyout content + var flyoutPage = new ContentPage + { + Title = "Master", + BackgroundColor = Colors.Blue + }; + + var page1Button = new Button + { + Text = "Page1", + AutomationId = "FlyoutItem", + HorizontalOptions = LayoutOptions.Start, + VerticalOptions = LayoutOptions.Center + }; + + flyoutPage.Content = new VerticalStackLayout + { + Children = { page1Button } + }; + + // Create the detail content + var detailPage = new ContentPage + { + Title = "Detail", + BackgroundColor = Colors.LightYellow + }; + + _button = new Button + { + Text = "Change Collapse Style", + AutomationId = "CollapseStyleButton", + }; + _button.Clicked += OnCollapseStyleValueChanged; + + detailPage.Content = new VerticalStackLayout + { + Children = { + new Microsoft.Maui.Controls.Label + { + Text = "Welcome to .NET MAUI!", + TextColor = Colors.Black, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }, + _button + } + }; + + // Set the flyout and detail pages + Flyout = flyoutPage; + Detail = detailPage; + } + + void OnCollapseStyleValueChanged(object sender, EventArgs e) + { + var currentCollapseStyle = this.On().GetCollapseStyle(); + var newCollapseStyle = currentCollapseStyle == CollapseStyle.Full + ? CollapseStyle.Partial + : CollapseStyle.Full; + + this.On().SetCollapseStyle(newCollapseStyle); + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue18200.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue18200.cs new file mode 100644 index 000000000000..ddb71b003a59 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue18200.cs @@ -0,0 +1,29 @@ +# if WINDOWS // It's a Windows specific API issue, so restricting the other platforms +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue18200 : _IssuesUITest +{ + public Issue18200(TestDevice device) + : base(device) + { } + + public override string Issue => "Flyout Page SetCollapseStyle doesn't have any change"; + + [Test] + [Category(UITestCategories.FlyoutPage)] + public void VerifyFlyoutCollapseStyleBehaviorChanges() + { + App.WaitForElement("CollapseStyleButton"); + App.Tap("CollapseStyleButton"); + App.TapFlyoutPageIcon(); + App.TapFlyoutPageIcon(); // Close the flyout + App.WaitForNoElement("FlyoutItem"); + App.Tap("CollapseStyleButton"); + App.WaitForElement("FlyoutItem"); + } +} +#endif \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/MauiNavigationView.cs b/src/Core/src/Platform/Windows/MauiNavigationView.cs index 791d495e3115..a1a56fbe4698 100644 --- a/src/Core/src/Platform/Windows/MauiNavigationView.cs +++ b/src/Core/src/Platform/Windows/MauiNavigationView.cs @@ -182,13 +182,14 @@ internal void UpdatePaneDisplayModeFromFlyoutBehavior(FlyoutBehavior flyoutBehav { case FlyoutBehavior.Flyout: IsPaneToggleButtonVisible = true; + var flyoutMode = FlyoutPaneDisplayMode ?? NavigationViewPaneDisplayMode.LeftMinimal; // WinUI bug: Setting PaneDisplayMode to the same value and updating SelectedItem during navigation // causes the selection and selected item indicator to not update correctly. // Workaround: Only set PaneDisplayMode when the value actually changes. // Related: https://github.com/microsoft/microsoft-ui-xaml/issues/9812 - if (PaneDisplayMode != NavigationViewPaneDisplayMode.LeftMinimal) + if (PaneDisplayMode != flyoutMode) { - PaneDisplayMode = NavigationViewPaneDisplayMode.LeftMinimal; + PaneDisplayMode = flyoutMode; } break; case FlyoutBehavior.Locked: @@ -371,6 +372,11 @@ internal static readonly DependencyProperty PaneToggleButtonWidthProperty new PropertyMetadata(DefaultPaneToggleButtonWidth, OnPaneToggleButtonSizeChanged)); private NavigationViewPaneDisplayMode? _pinPaneDisplayModeTo; + // Stores the preferred pane display mode for FlyoutBehavior.Flyout, set by CollapseStyle on Windows. + // When null, the default LeftMinimal is used. This ensures CollapseStyle.Partial (LeftCompact) survives + // layout-driven FlyoutBehavior re-evaluations (e.g. size/orientation changes). + internal NavigationViewPaneDisplayMode? FlyoutPaneDisplayMode { get; set; } + internal double PaneToggleButtonWidth { get => (double)GetValue(PaneToggleButtonWidthProperty);