I'm trying to make a UWP app with a NavigationView
. My problem is to find a way that the Header
changes for the current shown page. My app is based on the Microsoft UWP example "AppUIBasics". In the example the Header
of the NavigationView
shows always "Welcome" because its hardcoded but I want it to change depending on the selected page.
MainPage.xaml:
<NavigationView x:Name="NavView"
ItemInvoked="NavView_ItemInvoked"
SelectionChanged="NavView_SelectionChanged"
Loaded="NavView_Loaded"
Canvas.ZIndex="0">
<NavigationView.HeaderTemplate>
<DataTemplate>
<Grid Margin="24,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="appTitle" Style="{StaticResource TitleTextBlockStyle}"
FontSize="28"
VerticalAlignment="Center"
Text="Welcome"/>
<CommandBar Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
DefaultLabelPosition="Right"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}">
<AppBarButton Label="Refresh" Icon="Refresh"/>
<AppBarButton Label="Import" Icon="Import"/>
</CommandBar>
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
<NavigationView.MenuItems>
<NavigationViewItem x:Uid="HomeNavItem" Content="" Tag="home">
<NavigationViewItem.Icon>
<FontIcon Glyph=""/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItemSeparator/>
<NavigationViewItem x:Uid="ConnectionNavItem" Icon="world" Content="" Tag="connection"/>
<NavigationViewItem x:Uid="CameraNavItem" Icon="video" Content="" Tag="camera"/>
</NavigationView.MenuItems>
<Frame x:Name="rootFrame" Margin="24">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition/>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</NavigationView>
MainPage.xaml.cs:
public sealed partial class MainPage : Page {
public static MainPage Current;
public static Frame RootFrame = null;
//private RootFrameNavigationHelper _navHelper;
private ResourceLoader _resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
public MainPage() {
this.InitializeComponent();
this.Loaded += (sender, args) => {
Current = this;
var titleBar = Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().TitleBar;
};
}
public Frame AppFrame { get { return this.rootFrame; } }
private void NavView_Loaded(object sender, RoutedEventArgs e) {
// set the initial SelectedItem
foreach (NavigationViewItemBase item in NavView.MenuItems) {
if (item is NavigationViewItem && item.Tag.ToString() == "home") {
NavView.SelectedItem = item;
break;
}
}
}
private void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) {
if (args.IsSettingsInvoked) {
rootFrame.Navigate(typeof(SettingsPage));
} else {
// find NavigationViewItem with Content that equals InvokedItem
var item = sender.MenuItems.OfType<NavigationViewItem>().First(x => (string)x.Content == (string)args.InvokedItem);
NavView_Navigate(item as NavigationViewItem);
}
}
private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) {
if (args.IsSettingsSelected) {
rootFrame.Navigate(typeof(SettingsPage));
} else {
NavigationViewItem item = args.SelectedItem as NavigationViewItem;
NavView_Navigate(item);
}
}
private void NavView_Navigate(NavigationViewItem item) {
switch (item.Tag) {
case "home":
rootFrame.Navigate(typeof(HomePage)); break;
case "connection":
rootFrame.Navigate(typeof(ConnectionPage)); break;
case "camera":
rootFrame.Navigate(typeof(CameraPage)); break;
}
}
}
First you have to "un-hardcode" the header text from the template, Instead of the text you can use {Binding}
, which will provide the value assigned to the NavigationView
's Header
property:
<NavigationView.HeaderTemplate>
<DataTemplate>
<Grid Margin="24,10,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="appTitle" Style="{StaticResource TitleTextBlockStyle}"
FontSize="28"
VerticalAlignment="Center"
Text="{Binding}"/>
<CommandBar Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
DefaultLabelPosition="Right"
Background="{ThemeResource SystemControlBackgroundAltHighBrush}">
<AppBarButton Label="Refresh" Icon="Refresh"/>
<AppBarButton Label="Import" Icon="Import"/>
</CommandBar>
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
Now there are two places where you can set the header content. First is the SelectionChanged
event:
private void NavView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (args.IsSettingsSelected)
{
rootFrame.Navigate(typeof(SettingsPage));
NavView.Header = "Settings";
}
else
{
NavigationViewItem item = args.SelectedItem as NavigationViewItem;
NavView_Navigate(item);
//just example, maybe you want to Content or something else
NavView.Header = item.Tag.ToString();
}
}
You could also set the Header
from anywhere by adding a public method that sets the header:
public void SetHeader(string header)
{
NavView.Header = header;
}
And then using MainPage.Current.SetHeader( something )
anywhere you see fit.
The best solution however would be to create a base class other pages will derive from:
public class BasePage : Page
{
public virtual string Header => "";
}
And then each concrete Page could override this property:
public sealed partial class HomePage : BasePage
{
public override string Header => "Home";
public HomePage()
{
this.InitializeComponent();
}
}
Note - remember you have to update the base type of the page in XAML as well:
<local:BasePage xmlns:local="using:AppNamespace"
x:Class="AppNamespace.HomePage" ...>
</local:BasePage>
And in the MainPage
we then use data-binding to bind the Header
property to NavigationView
's Header
:
<NavigationView x:Name="NavView"
Header="{Binding Path=Content.Header, ElementName=rootFrame}" ...>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With