void NavigationView::OnApplyTemplate()

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();
}