winrt-xamlwinui-3

How can I dynamically apply Lightweight styling to NavigationView?


Changing the NavigationViewContentMargin dynamically, which determines the top margin of the NavigationView, does not change the appearance of the NavigationView dynamically.

Is there a way to dynamically change the top margin of NavigationView from the code?

top margin of NavigationView


Solution

  • You need to get the target Grid "NavigationViewContentMargin" is applied to. This Grid is named "ContentGrid".

    The tricky part is that NavigationViews have 2 Grids with the name "ContentGrid". The "ContentGrid" we need is the one that is inside a Grid with the name "ContentRoot". BTW, the other one is inside "Settings".

    First, we need to get the "ContentRoot" Grid, then get the "ContentGrid" we need.

    Check this example:

    MainWindow.xaml

    <Window
        x:Class="NavigationViewTests.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="using:Microsoft.UI.Xaml.Controls"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="using:NavigationViewTests"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid ColumnDefinitions="*,Auto">
            <Grid.Resources>
                <Thickness x:Key="NavigationViewContentMargin">0,48,0,0</Thickness>
            </Grid.Resources>
    
            <NavigationView
                x:Name="NavigationViewControl"
                Grid.Column="0"
                IsBackButtonVisible="Visible">
                <TextBlock Text="Content" />
            </NavigationView>
    
            <StackPanel Grid.Column="1">
                <NumberBox
                    x:Name="NavigationViewContentGridTopMarginNumber"
                    Header="NavigationView Top Margin"
                    ValueChanged="NumberBox_ValueChanged" />
            </StackPanel>
        </Grid>
    
    </Window>
    

    MainWindow.xaml.cs

    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using System.Linq;
    
    namespace NavigationViewTests;
    
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            this.NavigationViewControl.Loaded += (s, e) =>
            {
                this.NavigationViewContentGrid = GetNavigationViewContentGridInsideContentGrid();
    
                if (this.NavigationViewContentGrid is not null)
                {
                    this.NavigationViewContentGridTopMarginNumber.Value = this.NavigationViewContentGrid.Margin.Top;
                }
            };
        }
    
        private Grid? NavigationViewContentGrid { get; set; }
    
        private Grid? GetNavigationViewContentGridInsideContentGrid()
        {
            Grid? contentRoot = this.NavigationViewControl
                .FindChildrenOfType<Grid>()
                .Where(x => x.Name == "ContentRoot")
                .FirstOrDefault();
    
            return contentRoot?
               .FindChildrenOfType<Grid>()
               .Where(x => x.Name == "ContentGrid")
               .FirstOrDefault();
        }
    
        private void NumberBox_ValueChanged(NumberBox _, NumberBoxValueChangedEventArgs args)
        {
            if (NavigationViewContentGrid is not null)
            {
                Thickness currentMargin = this.NavigationViewContentGrid.Margin;
                this.NavigationViewContentGrid.Margin = new Thickness(
                    currentMargin.Left,
                    args.NewValue,
                    currentMargin.Right,
                    currentMargin.Bottom);
            }
        }
    }