From 191fcee2b82ba27155254cf504de3327f2345f41 Mon Sep 17 00:00:00 2001 From: Yimeng Wu Date: Fri, 8 Dec 2023 23:58:13 +0000 Subject: [PATCH] Port microsoft/microsoft-ui-xaml#4193 (#644) --- .../NavigationView/NavigationView.cs | 89 ++++++++++++------- .../NavigationView/NavigationView.xaml | 34 +++++-- .../Footer/PaneLayoutTestPage.xaml | 7 +- .../Footer/PaneLayoutTestPage.xaml.cs | 23 ++++- 4 files changed, 109 insertions(+), 44 deletions(-) diff --git a/ModernWpf.Controls/NavigationView/NavigationView.cs b/ModernWpf.Controls/NavigationView/NavigationView.cs index 9048146e..b8a78f94 100644 --- a/ModernWpf.Controls/NavigationView/NavigationView.cs +++ b/ModernWpf.Controls/NavigationView/NavigationView.cs @@ -81,7 +81,6 @@ public partial class NavigationView : ContentControl, IControlProtected const string c_itemsContainer = "ItemsContainerGrid"; const string c_itemsContainerRow = "ItemsContainerRow"; - const string c_visualItemsSeparator = "VisualItemsSeparator"; const string c_menuItemsScrollViewer = "MenuItemsScrollViewer"; const string c_footerItemsScrollViewer = "FooterItemsScrollViewer"; @@ -93,6 +92,9 @@ public partial class NavigationView : ContentControl, IControlProtected const string c_paneHeaderToggleButtonColumn = "PaneHeaderToggleButtonColumn"; const string c_paneHeaderContentBorderRow = "PaneHeaderContentBorderRow"; + const string c_separatorVisibleStateName = "SeparatorVisible"; + const string c_separatorCollapsedStateName = "SeparatorCollapsed"; + const int c_backButtonHeight = 40; const int c_backButtonWidth = 40; const int c_paneToggleButtonHeight = 40; @@ -100,6 +102,7 @@ public partial class NavigationView : ContentControl, IControlProtected const int c_toggleButtonHeightWhenShouldPreserveNavigationViewRS3Behavior = 56; const int c_backButtonRowDefinition = 1; const float c_paneElevationTranslationZ = 32; + const int c_paneItemsSeparatorHeight = 21; const int c_mainMenuBlockIndex = 0; const int c_footerMenuBlockIndex = 1; @@ -711,12 +714,11 @@ public override void OnApplyTemplate() m_itemsContainerRow = GetTemplateChildT(c_itemsContainerRow, controlProtected); m_menuItemsScrollViewer = GetTemplateChildT(c_menuItemsScrollViewer, controlProtected); m_footerItemsScrollViewer = GetTemplateChildT(c_footerItemsScrollViewer, controlProtected); - m_visualItemsSeparator = GetTemplateChildT(c_visualItemsSeparator, controlProtected); m_itemsContainerSizeChangedRevoker?.Revoke(); - if (GetTemplateChildT(c_itemsContainer, controlProtected) is { } itemsContainerRow) + if (GetTemplateChildT(c_itemsContainer, controlProtected) is { } itemsContainer) { - m_itemsContainerSizeChangedRevoker = new FrameworkElementSizeChangedRevoker(itemsContainerRow, OnItemsContainerSizeChanged); + m_itemsContainerSizeChangedRevoker = new FrameworkElementSizeChangedRevoker(itemsContainer, OnItemsContainerSizeChanged); } if (SharedHelpers.IsRS2OrHigher()) @@ -1553,25 +1555,44 @@ void UpdatePaneLayout() { if (!IsTopNavigationView()) { - double totalAvailableHeight; + var totalAvailableHeight = TotalAvailableHeight(); + double TotalAvailableHeight() { - totalAvailableHeight = init(); - double init() + if (m_itemsContainerRow is { } paneContentRow) { - if (m_itemsContainerRow is { } paneContentRow) + var itemsContainerMargin = ItemsContainerMargin(); + double ItemsContainerMargin() { - // 20px is the padding between the two item lists - if (m_leftNavFooterContentBorder is { } paneFooter) + if (m_itemsContainer is { } itemsContainer) { - return paneContentRow.ActualHeight - 29 - paneFooter.ActualHeight; + var margin = itemsContainer.Margin; + return margin.Top + margin.Bottom; } - else + return 0.0; + } + var availableHeight = paneContentRow.ActualHeight - itemsContainerMargin; + + // The -21 below is to account for the separator height that we need to subtract. + if (PaneFooter is { }) + { + availableHeight -= c_paneItemsSeparatorHeight; + if (m_leftNavFooterContentBorder is { } paneFooter) { - return paneContentRow.ActualHeight - 29; + availableHeight -= paneFooter.ActualHeight; } } - return 0.0; + else if (IsSettingsVisible) + { + availableHeight -= c_paneItemsSeparatorHeight; + } + else if (m_footerItemsSource is { } && m_menuItemsSource is { } && m_footerItemsSource.Count * m_menuItemsSource.Count > 0) + { + availableHeight -= c_paneItemsSeparatorHeight; + } + + return availableHeight; } + return 0.0; } // Only continue if we have a positive amount of space to manage. @@ -1594,44 +1615,44 @@ double init() { var footersActualHeight = footerItemsRepeater.ActualHeight; var menuItemsActualHeight = menuItems.ActualHeight; - if (totalAvailableHeight > menuItemsActualHeight + footersActualHeight) + + if (m_footerItemsSource.Count == 0 && !IsSettingsVisible) + { + VisualStateManager.GoToState(this, c_separatorCollapsedStateName, false); + return totalAvailableHeight; + } + else if (m_menuItemsSource.Count == 0) + { + footerItemsScrollViewer.MaxHeight = totalAvailableHeight; + VisualStateManager.GoToState(this, c_separatorCollapsedStateName, false); + return 0.0; + } + else if (totalAvailableHeight > menuItemsActualHeight + footersActualHeight) { // We have enough space for two so let everyone get as much as they need. footerItemsScrollViewer.MaxHeight = footersActualHeight; - if (m_visualItemsSeparator is { } separator) - { - separator.Visibility = Visibility.Collapsed; - } + VisualStateManager.GoToState(this, c_separatorCollapsedStateName, false); return totalAvailableHeight - footersActualHeight; } else if (menuItemsActualHeight <= totalAvailableHeightHalf) { // Footer items exceed over the half, so let's limit them. footerItemsScrollViewer.MaxHeight = totalAvailableHeight - menuItemsActualHeight; - if (m_visualItemsSeparator is { } separator) - { - separator.Visibility = Visibility.Visible; - } + VisualStateManager.GoToState(this, c_separatorVisibleStateName, false); return menuItemsActualHeight; } else if (footersActualHeight <= totalAvailableHeightHalf) { // Menu items exceed over the half, so let's limit them. footerItemsScrollViewer.MaxHeight = footersActualHeight; - if (m_visualItemsSeparator is { } separator) - { - separator.Visibility = Visibility.Visible; - } + VisualStateManager.GoToState(this, c_separatorVisibleStateName, false); return totalAvailableHeight - footersActualHeight; } else { // Both are more than half the height, so split evenly. footerItemsScrollViewer.MaxHeight = totalAvailableHeightHalf; - if (m_visualItemsSeparator is { } separator) - { - separator.Visibility = Visibility.Visible; - } + VisualStateManager.GoToState(this, c_separatorVisibleStateName, false); return totalAvailableHeightHalf; } } @@ -4172,6 +4193,10 @@ void PropertyChanged(DependencyPropertyChangedEventArgs args) { SyncItemTemplates(); } + else if (property == PaneFooterProperty) + { + UpdatePaneLayout(); + } } void UpdateNavigationViewItemsFactory() @@ -5746,7 +5771,6 @@ protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi) ColumnDefinition m_paneToggleButtonIconGridColumn; FrameworkElement m_paneTitleHolderFrameworkElement; FrameworkElement m_paneTitleFrameworkElement; - FrameworkElement m_visualItemsSeparator; Button m_paneSearchButton; Button m_backButton; Button m_closeButton; @@ -5787,6 +5811,7 @@ protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi) ColumnDefinition m_paneHeaderCloseButtonColumn; ColumnDefinition m_paneHeaderToggleButtonColumn; RowDefinition m_paneHeaderContentBorderRow; + FrameworkElement m_itemsContainer; NavigationViewItem m_lastItemExpandedIntoFlyout; diff --git a/ModernWpf.Controls/NavigationView/NavigationView.xaml b/ModernWpf.Controls/NavigationView/NavigationView.xaml index 328838c2..62ca2a5f 100644 --- a/ModernWpf.Controls/NavigationView/NavigationView.xaml +++ b/ModernWpf.Controls/NavigationView/NavigationView.xaml @@ -869,8 +869,16 @@ - + + + + + + + + + @@ -978,6 +986,17 @@ + + + + + + + + + + + @@ -1220,7 +1239,7 @@ - + @@ -1295,10 +1314,10 @@ - - - - + + + + @@ -1329,7 +1348,8 @@ - + diff --git a/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml b/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml index 4fb2434f..c29f39cc 100644 --- a/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml +++ b/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml @@ -10,7 +10,8 @@ mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> - + + @@ -22,6 +23,10 @@ + + diff --git a/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml.cs b/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml.cs index 07a505d0..14c70faa 100644 --- a/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml.cs +++ b/test/NavigationView_TestUI/Footer/PaneLayoutTestPage.xaml.cs @@ -21,7 +21,7 @@ public PaneLayoutTestPage() this.InitializeComponent(); - for (int i = 0; i < 4; i++) + for (int i = 0; i < 3; i++) { menuItems.Add( new NavigationViewItem() { @@ -31,7 +31,7 @@ public PaneLayoutTestPage() } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 3; i++) { footerItems.Add( new NavigationViewItem() { @@ -77,17 +77,23 @@ private void AddFooterItemButton_Click(object sender, RoutedEventArgs e) private void ResetCollectionsButton_Click(object sender, RoutedEventArgs e) { - for (int i = menuItems.Count - 1; i > 3; i--) + for (int i = menuItems.Count - 1; i > 2; i--) { menuItems.RemoveAt(i); } - for (int i = footerItems.Count - 1; i > 3; i--) + for (int i = footerItems.Count - 1; i > 2; i--) { footerItems.RemoveAt(i); } } + private void ClearCollectionsButton_Click(object sender, RoutedEventArgs e) + { + menuItems.Clear(); + footerItems.Clear(); + } + private void GetLayoutHeightsButton_Click(object sender, RoutedEventArgs e) { var itemsScroll = VisualTreeUtils.FindVisualChildByName(RootNavigationView, "MenuItemsScrollViewer"); @@ -95,5 +101,14 @@ private void GetLayoutHeightsButton_Click(object sender, RoutedEventArgs e) LayoutHeightsReport.Text = itemsScroll.ActualHeight + ";" + footerScroll.ActualHeight; } + private void IsSettingsEnabledCheckbox_Checked(object sender, RoutedEventArgs e) + { + RootNavigationView.IsSettingsVisible = true; + } + + private void IsSettingsEnabledCheckbox_UnChecked(object sender, RoutedEventArgs e) + { + RootNavigationView.IsSettingsVisible = false; + } } }