The NavigationView
control added in the Fall Creators Update of Windows 10 is a very useful tool for creating nice hamburger menu navigation that fits the guidelines of UWP apps. The control however includes a "header" area, that gives you a chance to provide a title of your page on the top. What if we don't want it?
The minimal problem
NavigationView
has a AlwaysShowHeader
property which allows you to specify if you want to display its header or not. This property works great, until the window size is too narrow and the NavigationView
's display mode switches to Minimal
.
Even when the header is empty, the content of your page is pushed down to make space for it, as though it was there. This is not very user friendly, especially on smaller screens (like phones), where every pixel matters.
Hidden in the template
If we dig into the default NavigationView
's style, we can find the following XAML definition inside:
<ContentControl x:Name="HeaderContent" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" HorizontalContentAlignment="Stretch" IsTabStop="False" MinHeight="48" VerticalContentAlignment="Stretch"/>
The problem is quite clear - the MinHeight
property is set to 48 effective pixels. In Minimal
mode, the header is always shown and even when it does not contain anything, it still takes up 48 precious pixels of your screen. The solution is very simple - we can just remove the MinHeight
property altogether.
Of course now we have one additional task - to make sure our page content count on the fact that top left corner is occluded by the hamburger button. This problem arises in the Minimal
mode only, so you can quite easily use a VisualStateTrigger
to add the required left margin to the top elements of your page when necessary. Following is the updated Style
. You can find it in the sample source code for this article on GitHub as well.
<Style x:Key="CustomNavigationMenuStyle" TargetType="NavigationView"> <Setter Property="PaneToggleButtonStyle" Value="{StaticResource PaneToggleButtonStyle}"/> <Setter Property="IsTabStop" Value="False"/> <Setter Property="HeaderTemplate"> <Setter.Value> <DataTemplate> <Grid Margin="12,5,0,11" VerticalAlignment="Stretch"> <TextBlock x:Name="Header" Style="{StaticResource TitleTextBlockStyle}" Text="{Binding}" TextWrapping="NoWrap" VerticalAlignment="Bottom"/> </Grid> </DataTemplate> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="NavigationView"> <Grid x:Name="RootGrid"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="DisplayModeGroup"> <VisualState x:Name="Compact"/> <VisualState x:Name="Expanded"> <VisualState.Setters> <Setter Target="RootSplitView.PaneBackground" Value="{ThemeResource NavigationViewExpandedPaneBackground}"/> </VisualState.Setters> </VisualState> <VisualState x:Name="Minimal"> <VisualState.Setters> <Setter Target="HeaderContent.Margin" Value="48,0,0,0"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="TogglePaneGroup"> <VisualState x:Name="TogglePaneButtonVisible"/> <VisualState x:Name="TogglePaneButtonCollapsed"> <VisualState.Setters> <Setter Target="TogglePaneButton.Visibility" Value="Collapsed"/> <Setter Target="PaneContentGridToggleButtonRow.Height" Value="4"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="HeaderGroup"> <VisualState x:Name="HeaderVisible"/> <VisualState x:Name="HeaderCollapsed"> <VisualState.Setters> <Setter Target="HeaderContent.Visibility" Value="Collapsed"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="SettingsGroup"> <VisualState x:Name="SettingsVisible"/> <VisualState x:Name="SettingsCollapsed"> <VisualState.Setters> <Setter Target="SettingsNavPaneItem.Visibility" Value="Collapsed"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="AutoSuggestGroup"> <VisualState x:Name="AutoSuggestBoxVisible"/> <VisualState x:Name="AutoSuggestBoxCollapsed"> <VisualState.Setters> <Setter Target="AutoSuggestArea.Visibility" Value="Collapsed"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="PaneStateGroup"> <VisualState x:Name="NotClosedCompact"/> <VisualState x:Name="ClosedCompact"> <VisualState.Setters> <Setter Target="PaneAutoSuggestBoxPresenter.Visibility" Value="Collapsed"/> <Setter Target="PaneAutoSuggestButton.Visibility" Value="Visible"/> </VisualState.Setters> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="TitleBarVisibilityGroup"> <VisualState x:Name="TitleBarVisible"/> <VisualState x:Name="TitleBarCollapsed"> <VisualState.Setters> <Setter Target="PaneButtonGrid.Margin" Value="0,32,0,0"/> <Setter Target="PaneContentGrid.Margin" Value="0,32,0,0"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid HorizontalAlignment="Left" Margin="0,0,0,8" VerticalAlignment="Top" Width="{StaticResource PaneToggleButtonSize}" Canvas.ZIndex="100"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid x:Name="TogglePaneTopPadding"/> <Button x:Name="TogglePaneButton" AutomationProperties.LandmarkType="Navigation" Grid.Row="1" Style="{TemplateBinding PaneToggleButtonStyle}"/> </Grid> <SplitView x:Name="RootSplitView" Background="{TemplateBinding Background}" CompactPaneLength="{TemplateBinding CompactPaneLength}" DisplayMode="Inline" IsTabStop="False" IsPaneOpen="{Binding IsPaneOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" OpenPaneLength="{TemplateBinding OpenPaneLength}" PaneBackground="{ThemeResource NavigationViewDefaultPaneBackground}"> <SplitView.Pane> <Grid x:Name="PaneContentGrid"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition x:Name="PaneContentGridToggleButtonRow" Height="56"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="8"/> </Grid.RowDefinitions> <Grid x:Name="ContentPaneTopPadding"/> <Grid x:Name="AutoSuggestArea" Height="40" Grid.Row="2" VerticalAlignment="Center"> <ContentControl x:Name="PaneAutoSuggestBoxPresenter" Content="{TemplateBinding AutoSuggestBox}" HorizontalContentAlignment="Stretch" IsTabStop="False" Margin="12,0,12,0" VerticalContentAlignment="Center"/> <Button x:Name="PaneAutoSuggestButton" Content="" MinHeight="40" Style="{TemplateBinding PaneToggleButtonStyle}" Visibility="Collapsed" Width="{TemplateBinding CompactPaneLength}"/> </Grid> <NavigationViewList x:Name="MenuItemsHost" ItemContainerStyleSelector="{TemplateBinding MenuItemContainerStyleSelector}" ItemContainerStyle="{TemplateBinding MenuItemContainerStyle}" ItemTemplate="{TemplateBinding MenuItemTemplate}" IsItemClickEnabled="True" ItemsSource="{TemplateBinding MenuItemsSource}" ItemTemplateSelector="{TemplateBinding MenuItemTemplateSelector}" Margin="0,0,0,20" Grid.Row="3" SelectionMode="Single" SelectedItem="{TemplateBinding SelectedItem}"/> <Border x:Name="FooterContentBorder" Child="{TemplateBinding PaneFooter}" Grid.Row="4"/> <NavigationViewItem x:Name="SettingsNavPaneItem" Grid.Row="5"> <NavigationViewItem.Icon> <SymbolIcon Symbol="Setting"/> </NavigationViewItem.Icon> </NavigationViewItem> </Grid> </SplitView.Pane> <Grid x:Name="ContentGrid"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <ContentControl x:Name="HeaderContent" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" HorizontalContentAlignment="Stretch" IsTabStop="False" VerticalContentAlignment="Stretch"/> <ContentPresenter Content="{TemplateBinding Content}" Grid.Row="1"/> </Grid> </SplitView> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
Sample code
Source code for this article is available on my GitHub.
Summary
We have shown how to make sure that NavigationView
does not show any header even in the Minimal
display mode and how to give our content a chance to shine on the whole area available for our app.