Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UWP NavigationView Header Title

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="&#xE10F;"/>
            </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;
        }
    }
}
like image 846
cybertronic Avatar asked Dec 18 '22 00:12

cybertronic


1 Answers

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>

Simple solution

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

Better solution

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.

Best solution

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}" ...>
like image 186
Martin Zikmund Avatar answered Dec 28 '22 09:12

Martin Zikmund