in dev/NavigationView/NavigationView.cpp [384:717]
void NavigationView::OnApplyTemplate()
{
// Stop update anything because of PropertyChange during OnApplyTemplate. Update them all together at the end of this function
m_appliedTemplate = false;
auto scopeGuard = gsl::finally([this]()
{
m_fromOnApplyTemplate = false;
});
m_fromOnApplyTemplate = true;
UnhookEventsAndClearFields();
winrt::IControlProtected controlProtected = *this;
// Set up the pane toggle button click handler
if (auto paneToggleButton = GetTemplateChildT<winrt::Button>(c_togglePaneButtonName, controlProtected))
{
m_paneToggleButton.set(paneToggleButton);
m_paneToggleButtonClickRevoker = paneToggleButton.Click(winrt::auto_revoke, { this, &NavigationView::OnPaneToggleButtonClick });
SetPaneToggleButtonAutomationName();
if (SharedHelpers::IsRS3OrHigher())
{
winrt::KeyboardAccelerator keyboardAccelerator;
keyboardAccelerator.Key(winrt::VirtualKey::Back);
keyboardAccelerator.Modifiers(winrt::VirtualKeyModifiers::Windows);
paneToggleButton.KeyboardAccelerators().Append(keyboardAccelerator);
}
}
m_leftNavPaneHeaderContentBorder.set(GetTemplateChildT<winrt::ContentControl>(c_leftNavPaneHeaderContentBorder, controlProtected));
m_leftNavPaneCustomContentBorder.set(GetTemplateChildT<winrt::ContentControl>(c_leftNavPaneCustomContentBorder, controlProtected));
m_leftNavFooterContentBorder.set(GetTemplateChildT<winrt::ContentControl>(c_leftNavFooterContentBorder, controlProtected));
m_paneHeaderOnTopPane.set(GetTemplateChildT<winrt::ContentControl>(c_paneHeaderOnTopPane, controlProtected));
m_paneTitleOnTopPane.set(GetTemplateChildT<winrt::ContentControl>(c_paneTitleOnTopPane, controlProtected));
m_paneCustomContentOnTopPane.set(GetTemplateChildT<winrt::ContentControl>(c_paneCustomContentOnTopPane, controlProtected));
m_paneFooterOnTopPane.set(GetTemplateChildT<winrt::ContentControl>(c_paneFooterOnTopPane, controlProtected));
// Get a pointer to the root SplitView
if (auto splitView = GetTemplateChildT<winrt::SplitView>(c_rootSplitViewName, controlProtected))
{
m_rootSplitView.set(splitView);
m_splitViewIsPaneOpenChangedRevoker = RegisterPropertyChanged(splitView,
winrt::SplitView::IsPaneOpenProperty(),
{ this, &NavigationView::OnSplitViewClosedCompactChanged });
m_splitViewDisplayModeChangedRevoker = RegisterPropertyChanged(splitView,
winrt::SplitView::DisplayModeProperty(),
{ this, &NavigationView::OnSplitViewClosedCompactChanged });
if (SharedHelpers::IsRS3OrHigher()) // These events are new to RS3/v5 API
{
m_splitViewPaneClosedRevoker = splitView.PaneClosed(winrt::auto_revoke, { this, &NavigationView::OnSplitViewPaneClosed });
m_splitViewPaneClosingRevoker = splitView.PaneClosing(winrt::auto_revoke, { this, &NavigationView::OnSplitViewPaneClosing });
m_splitViewPaneOpenedRevoker = splitView.PaneOpened(winrt::auto_revoke, { this, &NavigationView::OnSplitViewPaneOpened });
m_splitViewPaneOpeningRevoker = splitView.PaneOpening(winrt::auto_revoke, { this, &NavigationView::OnSplitViewPaneOpening });
}
UpdateIsClosedCompact();
}
m_topNavGrid.set(GetTemplateChildT<winrt::Grid>(c_topNavGrid, controlProtected));
// Change code to NOT do this if we're in top nav mode, to prevent it from being realized:
if (auto leftNavRepeater = GetTemplateChildT<winrt::ItemsRepeater>(c_menuItemsHost, controlProtected))
{
m_leftNavRepeater.set(leftNavRepeater);
// API is currently in preview, so setting this via code.
// Disabling virtualization for now because of https://github.com/microsoft/microsoft-ui-xaml/issues/2095
if (auto stackLayout = leftNavRepeater.Layout().try_as<winrt::StackLayout>())
{
auto stackLayoutImpl = winrt::get_self<StackLayout>(stackLayout);
stackLayoutImpl->DisableVirtualization(true);
}
m_leftNavItemsRepeaterElementPreparedRevoker = leftNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared });
m_leftNavItemsRepeaterElementClearingRevoker = leftNavRepeater.ElementClearing(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementClearing });
m_leftNavRepeaterLoadedRevoker = leftNavRepeater.Loaded(winrt::auto_revoke, { this, &NavigationView::OnRepeaterLoaded });
m_leftNavRepeaterGettingFocusRevoker = leftNavRepeater.GettingFocus(winrt::auto_revoke, { this, &NavigationView::OnRepeaterGettingFocus });
leftNavRepeater.ItemTemplate(*m_navigationViewItemsFactory);
}
// Change code to NOT do this if we're in left nav mode, to prevent it from being realized:
if (auto topNavRepeater = GetTemplateChildT<winrt::ItemsRepeater>(c_topNavMenuItemsHost, controlProtected))
{
m_topNavRepeater.set(topNavRepeater);
// API is currently in preview, so setting this via code
if (auto stackLayout = topNavRepeater.Layout().try_as<winrt::StackLayout>())
{
auto stackLayoutImpl = winrt::get_self<StackLayout>(stackLayout);
stackLayoutImpl->DisableVirtualization(true);
}
m_topNavItemsRepeaterElementPreparedRevoker = topNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared });
m_topNavItemsRepeaterElementClearingRevoker = topNavRepeater.ElementClearing(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementClearing });
m_topNavRepeaterLoadedRevoker = topNavRepeater.Loaded(winrt::auto_revoke, { this, &NavigationView::OnRepeaterLoaded });
m_topNavRepeaterGettingFocusRevoker = topNavRepeater.GettingFocus(winrt::auto_revoke, { this, &NavigationView::OnRepeaterGettingFocus });
topNavRepeater.ItemTemplate(*m_navigationViewItemsFactory);
}
// Change code to NOT do this if we're in left nav mode, to prevent it from being realized:
if (auto topNavListOverflowRepeater = GetTemplateChildT<winrt::ItemsRepeater>(c_topNavMenuItemsOverflowHost, controlProtected))
{
m_topNavRepeaterOverflowView.set(topNavListOverflowRepeater);
// API is currently in preview, so setting this via code.
// Disabling virtualization for now because of https://github.com/microsoft/microsoft-ui-xaml/issues/2095
if (auto stackLayout = topNavListOverflowRepeater.Layout().try_as<winrt::StackLayout>())
{
auto stackLayoutImpl = winrt::get_self<StackLayout>(stackLayout);
stackLayoutImpl->DisableVirtualization(true);
}
m_topNavOverflowItemsRepeaterElementPreparedRevoker = topNavListOverflowRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared });
m_topNavOverflowItemsRepeaterElementClearingRevoker = topNavListOverflowRepeater.ElementClearing(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementClearing });
topNavListOverflowRepeater.ItemTemplate(*m_navigationViewItemsFactory);
}
if (auto topNavOverflowButton = GetTemplateChildT<winrt::Button>(c_topNavOverflowButton, controlProtected))
{
m_topNavOverflowButton.set(topNavOverflowButton);
winrt::AutomationProperties::SetName(topNavOverflowButton, ResourceAccessor::GetLocalizedStringResource(SR_NavigationOverflowButtonName));
topNavOverflowButton.Content(box_value(ResourceAccessor::GetLocalizedStringResource(SR_NavigationOverflowButtonText)));
auto visual = winrt::ElementCompositionPreview::GetElementVisual(topNavOverflowButton);
CreateAndAttachHeaderAnimation(visual);
auto const toolTip = winrt::ToolTipService::GetToolTip(topNavOverflowButton);
if (!toolTip)
{
auto const tooltip = winrt::ToolTip();
tooltip.Content(box_value(ResourceAccessor::GetLocalizedStringResource(SR_NavigationOverflowButtonToolTip)));
winrt::ToolTipService::SetToolTip(topNavOverflowButton, tooltip);
}
if (auto const flyoutBase = topNavOverflowButton.Flyout())
{
if (winrt::IFlyoutBase6 topNavOverflowButtonAsFlyoutBase6 = flyoutBase)
{
topNavOverflowButtonAsFlyoutBase6.ShouldConstrainToRootBounds(false);
}
m_flyoutClosingRevoker = flyoutBase.Closing(winrt::auto_revoke, { this, &NavigationView::OnFlyoutClosing });
}
}
// Change code to NOT do this if we're in top nav mode, to prevent it from being realized:
if (auto leftFooterMenuNavRepeater = GetTemplateChildT<winrt::ItemsRepeater>(c_footerMenuItemsHost, controlProtected))
{
m_leftNavFooterMenuRepeater.set(leftFooterMenuNavRepeater);
// API is currently in preview, so setting this via code.
// Disabling virtualization for now because of https://github.com/microsoft/microsoft-ui-xaml/issues/2095
if (auto stackLayout = leftFooterMenuNavRepeater.Layout().try_as<winrt::StackLayout>())
{
auto stackLayoutImpl = winrt::get_self<StackLayout>(stackLayout);
stackLayoutImpl->DisableVirtualization(true);
}
m_leftNavFooterMenuItemsRepeaterElementPreparedRevoker = leftFooterMenuNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared });
m_leftNavFooterMenuItemsRepeaterElementClearingRevoker = leftFooterMenuNavRepeater.ElementClearing(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementClearing });
m_leftNavFooterMenuRepeaterLoadedRevoker = leftFooterMenuNavRepeater.Loaded(winrt::auto_revoke, { this, &NavigationView::OnRepeaterLoaded });
m_leftNavFooterMenuRepeaterGettingFocusRevoker = leftFooterMenuNavRepeater.GettingFocus(winrt::auto_revoke, { this, &NavigationView::OnRepeaterGettingFocus });
leftFooterMenuNavRepeater.ItemTemplate(*m_navigationViewItemsFactory);
}
// Change code to NOT do this if we're in left nav mode, to prevent it from being realized:
if (auto topFooterMenuNavRepeater = GetTemplateChildT<winrt::ItemsRepeater>(c_topNavFooterMenuItemsHost, controlProtected))
{
m_topNavFooterMenuRepeater.set(topFooterMenuNavRepeater);
// API is currently in preview, so setting this via code.
// Disabling virtualization for now because of https://github.com/microsoft/microsoft-ui-xaml/issues/2095
if (auto stackLayout = topFooterMenuNavRepeater.Layout().try_as<winrt::StackLayout>())
{
auto stackLayoutImpl = winrt::get_self<StackLayout>(stackLayout);
stackLayoutImpl->DisableVirtualization(true);
}
m_topNavFooterMenuItemsRepeaterElementPreparedRevoker = topFooterMenuNavRepeater.ElementPrepared(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementPrepared });
m_topNavFooterMenuItemsRepeaterElementClearingRevoker = topFooterMenuNavRepeater.ElementClearing(winrt::auto_revoke, { this, &NavigationView::OnRepeaterElementClearing });
m_topNavFooterMenuRepeaterLoadedRevoker = topFooterMenuNavRepeater.Loaded(winrt::auto_revoke, { this, &NavigationView::OnRepeaterLoaded });
m_topNavFooterMenuRepeaterGettingFocusRevoker = topFooterMenuNavRepeater.GettingFocus(winrt::auto_revoke, { this, &NavigationView::OnRepeaterGettingFocus });
topFooterMenuNavRepeater.ItemTemplate(*m_navigationViewItemsFactory);
}
m_topNavContentOverlayAreaGrid.set(GetTemplateChildT<winrt::Border>(c_topNavContentOverlayAreaGrid, controlProtected));
m_leftNavPaneAutoSuggestBoxPresenter.set(GetTemplateChildT<winrt::ContentControl>(c_leftNavPaneAutoSuggestBoxPresenter, controlProtected));
m_topNavPaneAutoSuggestBoxPresenter.set(GetTemplateChildT<winrt::ContentControl>(c_topNavPaneAutoSuggestBoxPresenter, controlProtected));
// Get pointer to the pane content area, for use in the selection indicator animation
m_paneContentGrid.set(GetTemplateChildT<winrt::UIElement>(c_paneContentGridName, controlProtected));
m_contentLeftPadding.set(GetTemplateChildT<winrt::FrameworkElement>(c_contentLeftPadding, controlProtected));
m_paneHeaderCloseButtonColumn.set(GetTemplateChildT<winrt::ColumnDefinition>(c_paneHeaderCloseButtonColumn, controlProtected));
m_paneHeaderToggleButtonColumn.set(GetTemplateChildT<winrt::ColumnDefinition>(c_paneHeaderToggleButtonColumn, controlProtected));
m_paneHeaderContentBorderRow.set(GetTemplateChildT<winrt::RowDefinition>(c_paneHeaderContentBorderRow, controlProtected));
m_paneTitleFrameworkElement.set(GetTemplateChildT<winrt::FrameworkElement>(c_paneTitleFrameworkElement, controlProtected));
m_paneTitlePresenter.set(GetTemplateChildT<winrt::ContentControl>(c_paneTitlePresenter, controlProtected));
if (auto paneTitleHolderFrameworkElement = GetTemplateChildT<winrt::FrameworkElement>(c_paneTitleHolderFrameworkElement, controlProtected))
{
m_paneTitleHolderFrameworkElement.set(paneTitleHolderFrameworkElement);
m_paneTitleHolderFrameworkElementSizeChangedRevoker = paneTitleHolderFrameworkElement.SizeChanged(winrt::auto_revoke, { this, &NavigationView::OnPaneTitleHolderSizeChanged });
}
// Set automation name on search button
if (auto button = GetTemplateChildT<winrt::Button>(c_searchButtonName, controlProtected))
{
m_paneSearchButton.set(button);
m_paneSearchButtonClickRevoker = button.Click(winrt::auto_revoke, { this, &NavigationView::OnPaneSearchButtonClick });
auto searchButtonName = ResourceAccessor::GetLocalizedStringResource(SR_NavigationViewSearchButtonName);
winrt::AutomationProperties::SetName(button, searchButtonName);
auto toolTip = winrt::ToolTip();
toolTip.Content(box_value(searchButtonName));
winrt::ToolTipService::SetToolTip(button, toolTip);
}
if (auto backButton = GetTemplateChildT<winrt::Button>(c_navViewBackButton, controlProtected))
{
m_backButton.set(backButton);
m_backButtonClickedRevoker = backButton.Click(winrt::auto_revoke, { this, &NavigationView::OnBackButtonClicked });
winrt::hstring navigationName = ResourceAccessor::GetLocalizedStringResource(SR_NavigationBackButtonName);
winrt::AutomationProperties::SetName(backButton, navigationName);
}
// Register for changes in title bar layout
if (auto coreTitleBar = winrt::CoreApplication::GetCurrentView().TitleBar())
{
m_coreTitleBar.set(coreTitleBar);
m_titleBarMetricsChangedRevoker = coreTitleBar.LayoutMetricsChanged(winrt::auto_revoke, { this, &NavigationView::OnTitleBarMetricsChanged });
m_titleBarIsVisibleChangedRevoker = coreTitleBar.IsVisibleChanged(winrt::auto_revoke, { this, &NavigationView::OnTitleBarIsVisibleChanged });
if (ShouldPreserveNavigationViewRS4Behavior())
{
m_togglePaneTopPadding.set(GetTemplateChildT<winrt::FrameworkElement>(c_togglePaneTopPadding, controlProtected));
m_contentPaneTopPadding.set(GetTemplateChildT<winrt::FrameworkElement>(c_contentPaneTopPadding, controlProtected));
}
}
if (auto backButtonToolTip = GetTemplateChildT<winrt::ToolTip>(c_navViewBackButtonToolTip, controlProtected))
{
winrt::hstring navigationBackButtonToolTip = ResourceAccessor::GetLocalizedStringResource(SR_NavigationBackButtonToolTip);
backButtonToolTip.Content(box_value(navigationBackButtonToolTip));
}
if (auto closeButton = GetTemplateChildT<winrt::Button>(c_navViewCloseButton, controlProtected))
{
m_closeButton.set(closeButton);
m_closeButtonClickedRevoker = closeButton.Click(winrt::auto_revoke, { this, &NavigationView::OnPaneToggleButtonClick });
winrt::hstring navigationName = ResourceAccessor::GetLocalizedStringResource(SR_NavigationCloseButtonName);
winrt::AutomationProperties::SetName(closeButton, navigationName);
}
if (auto closeButtonToolTip = GetTemplateChildT<winrt::ToolTip>(c_navViewCloseButtonToolTip, controlProtected))
{
winrt::hstring navigationCloseButtonToolTip = ResourceAccessor::GetLocalizedStringResource(SR_NavigationButtonOpenName);
closeButtonToolTip.Content(box_value(navigationCloseButtonToolTip));
}
m_itemsContainerRow.set(GetTemplateChildT<winrt::RowDefinition>(c_itemsContainerRow, controlProtected));
m_menuItemsScrollViewer.set(GetTemplateChildT<winrt::FrameworkElement>(c_menuItemsScrollViewer, controlProtected));
m_footerItemsScrollViewer.set(GetTemplateChildT<winrt::FrameworkElement>(c_footerItemsScrollViewer, controlProtected));
m_itemsContainerSizeChangedRevoker.revoke();
if (const auto itemsContainer = GetTemplateChildT<winrt::FrameworkElement>(c_itemsContainer, controlProtected))
{
m_itemsContainer.set(itemsContainer);
m_itemsContainerSizeChangedRevoker = itemsContainer.SizeChanged(winrt::auto_revoke, { this,&NavigationView::OnItemsContainerSizeChanged });
}
if (SharedHelpers::IsRS2OrHigher())
{
// Get hold of the outermost grid and enable XYKeyboardNavigationMode
// However, we only want this to work in the content pane + the hamburger button (which is not inside the splitview)
// so disable it on the grid in the content area of the SplitView
if (auto rootGrid = GetTemplateChildT<winrt::Grid>(c_rootGridName, controlProtected))
{
rootGrid.XYFocusKeyboardNavigation(winrt::XYFocusKeyboardNavigationMode::Enabled);
}
if (auto contentGrid = GetTemplateChildT<winrt::Grid>(c_contentGridName, controlProtected))
{
contentGrid.XYFocusKeyboardNavigation(winrt::XYFocusKeyboardNavigationMode::Disabled);
}
}
m_accessKeyInvokedRevoker = AccessKeyInvoked(winrt::auto_revoke, { this, &NavigationView::OnAccessKeyInvoked });
if (SharedHelpers::Is21H1OrHigher())
{
m_shadowCaster.set(GetTemplateChildT<winrt::Grid>(c_shadowCaster, controlProtected));
m_shadowCasterEaseOutStoryboard.set(GetTemplateChildT<winrt::Storyboard>(c_shadowCasterEaseOutStoryboard, controlProtected));
}
else
{
UpdatePaneShadow();
}
m_appliedTemplate = true;
// Do initial setup
UpdatePaneDisplayMode();
UpdateHeaderVisibility();
UpdatePaneTitleFrameworkElementParents();
UpdateTitleBarPadding();
UpdatePaneTabFocusNavigation();
UpdateBackAndCloseButtonsVisibility();
UpdateSingleSelectionFollowsFocusTemplateSetting();
UpdatePaneVisibility();
UpdateVisualState();
UpdatePaneTitleMargins();
UpdatePaneLayout();
UpdatePaneOverlayGroup();
}