Search code examples
c#xamluwp

How can I customize appearance of XAML Navigation View Pane


I have a XAML Navigation View control with "Top" PaneDisplayMode.

I would like to increase the pane height and centrally align menu items.

Increasing NavigationViewItem height does not make the pane taller. And changing alignment settings does not affect menu item poistion in the pane.

How can I do this?

<Page ... xmlns:muxc="using:Microsoft.UI.Xaml.Controls" ... >
<Grid>
    <muxc:NavigationView x:Name="NavView"
                         Loaded="NavView_Loaded"
                         ItemInvoked="NavView_ItemInvoked"
                         BackRequested="NavView_BackRequested"
                         PaneDisplayMode="Top">

        <muxc:NavigationView.MenuItems>
            <muxc:NavigationViewItem Tag="home" Icon="Home" Content="Home"/>
            <muxc:NavigationViewItemSeparator/>
            <muxc:NavigationViewItemHeader x:Name="MainPagesHeader"
                                           Content="Main pages"/>
            <muxc:NavigationViewItem Tag="apps" Content="Apps">
                <muxc:NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB3C;"/>
                </muxc:NavigationViewItem.Icon>
            </muxc:NavigationViewItem>
            <muxc:NavigationViewItem Tag="games" Content="Games">
                <muxc:NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7FC;"/>
                </muxc:NavigationViewItem.Icon>
            </muxc:NavigationViewItem>
            <muxc:NavigationViewItem Tag="music" Icon="Audio" Content="Music"/>
        </muxc:NavigationView.MenuItems>

    

        <ScrollViewer>
            <Frame x:Name="ContentFrame" Padding="12,0,12,24" IsTabStop="True"
                   NavigationFailed="ContentFrame_NavigationFailed"/>
        </ScrollViewer>
    </muxc:NavigationView>


</Grid>
</Page>

Solution

  • Could not find the answer so solved it by removing navigation view and implementing something similar myself, sharing here in case someone else is in the same pickle. So this is more of a workaround than an answer. If someone offers a better answer I will accept it.

    in NavigationRoot.xaml I have a grid with stack panel for "pane" and frame for pages. Note that buttons have a tag that matches the page tag which I use in navigation (don't judge).

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="4*"/>
        </Grid.RowDefinitions>
    
        <StackPanel x:Name="Pane" Orientation="Horizontal" HorizontalAlignment="Center" Margin="10">
            <ToggleButton  x:Name="HomeButton" Content="Home"  Tag="home" Click="Button_Click" Width="100" Margin="10"/>
            <ToggleButton  x:Name="SettingsButton" Content="Settings" Tag="settings" Click="Button_Click" Width="100" Margin="10"/>
        </StackPanel>
        <Frame Grid.Row="1" x:Name="RootContentFrame"/>
    </Grid>
    

    In code behind I keep track of "CurrentPageTag" and I have a list of pages.

         private string CurrentPageTag;
        
        // List of ValueTuple holding the Navigation Tag and the relative Navigation Page
        private readonly List<(string Tag, Type Page)> _pages = new List<(string Tag, Type Page)>
        {
            ("home", typeof(MainPage)),
            ("settings", typeof(SettingsPage))
        };
    

    In the button_click event for the toggle buttons I get the button tag and navigate to that page:

     string TargetPageTag = (sender as ToggleButton).Tag.ToString();
     //cancel navigation of current and target are the same
     if (TargetPageTag == CurrentPageTag)
     {
         return;
     }
     else
     {
           /*
           you can check that page can be navigated away from here (form 
           validation and the like) and exit early if validation fails. 
           I actually use a global "cancel navigation" variable 
           that pages can set if they are in an incomplete state 
           and should not be navigated away from.
           */
     
       //navigate to target page
       Type targetPage = _pages.FirstOrDefault(p => p.Tag.Equals(targetPageTag)).Page;
       RootContentFrame.Navigate(targetPage);
       CurrentPageTag = targetPageTag;
       return;
     }
    

    This gives you basic "navigation view" like functionality with actually heaps less code (but without the ability to change the pane layout on the fly).

    What I omitted here for brevity is that I had to style toggle buttons to be more suitable for this purpose. Also, I had them working more like radio buttons where only one is checked at any one time. Perhaps radio buttons should have been used with more styling (but I hate styling so went this route)?