Choosing a specific master page for each Windows Store App page

At 6Wunderkinder we are creating the Windows Store Version (WinRT) of Wunderlist. Our app basically has two kinds of pages. One is where you are logged in and one is where you are not logged in. We use a master page to take care of backgrounds and other stuff that is shared across pages. When all pages are the same, you just replace Window.Current.Content as Frame (in App.xaml.cs) with your master page (as described by Fons Sonnemans) and load all other pages within that masterpage. But what if you want to support multiple masterpages?

masterpages

Well, it turns out it is very easy to do this and you can even use the default Frame from App.xaml.cs

Download a demo project or follow the next steps to create Application Navigation where pages can use a specific masterpage or no masterpage at all!

Step 1: Create a Masterpage

<Page
    x:Class="MasterPageTest.MasterPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="#FF363333">
        <Grid.RowDefinitions>
            <RowDefinition Height="43*"/>
            <RowDefinition Height="213*"/>
        </Grid.RowDefinitions>
        <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Master!" VerticalAlignment="Center" FontSize="48" Margin="100,0,0,0"/>
        <TextBox HorizontalAlignment="Center" x:Name="search" TextWrapping="Wrap" Text="TextBlock1" VerticalAlignment="Center" FontSize="18.667" Width="200"/>

        <Frame x:Name="ContentFrame" Content="Frame" Grid.Row="1" Margin="100"/>

        <StackPanel Margin="0,0,100,0" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Content="MainPage" Click="ButtonBase_OnClick1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Height="80" Margin="0"/>
            <Button Content="Second Page" Click="ButtonBase_OnClick2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Height="80" Margin="0"/>
            <Button Content="Logout" Click="ButtonBase_OnClick3" HorizontalAlignment="Center" VerticalAlignment="Center" Width="150" Height="80" Margin="0"/>
        </StackPanel>
    </Grid>
</Page>

Don’t worry about the Button Click Handlers. We will implement them later. Important in the code above is the placeholder for your content:

<Frame x:Name="ContentFrame" Content="Frame" Grid.Row="1" Margin="100"/>

Step 2: Create a navigation helper

public class NavigateService {
    private static readonly Lazy<NavigateService> lazy = new Lazy<NavigateService>(() => new NavigateService());
    public static NavigateService Instance { get { return lazy.Value; } }

    public Frame Frame { get; set; }

    public void Navigate(Type pageType) {
        Frame.Navigate(pageType);
    }

    public void Navigate(Type pageType, Type masterPageType) {
        var masterPage = Frame.Content as Page;
        if (masterPage != null && masterPage.GetType() != masterPageType) {
            Frame.Navigate(masterPageType);
            masterPage = Frame.Content as Page;
        }
        var contentFrame = masterPage.FindName("ContentFrame") as Frame;
        contentFrame.Navigate(pageType);
    }
}

Step 3: Assign the rootFrame to the NavigationService

protected override void OnLaunched(LaunchActivatedEventArgs e) {
    Frame rootFrame = Window.Current.Content as Frame;

    if (rootFrame == null) {
        rootFrame = new Frame();
        Window.Current.Content = rootFrame;
    }

    NavigateService.Instance.Frame = rootFrame;

    if (rootFrame.Content == null) {
        rootFrame.Navigate(typeof(LoginPage), e.Arguments);
    }
    Window.Current.Activate();
}

Step 4: Add click handlers to navigate

private void ButtonBase_OnClick1(object sender, RoutedEventArgs e) {
    NavigateService.Instance.Navigate(typeof(MainPage), typeof(MasterPage));
}
private void ButtonBase_OnClick2(object sender, RoutedEventArgs e) {
    NavigateService.Instance.Navigate(typeof(SecondPage), typeof(MasterPage));
}
private void ButtonBase_OnClick3(object sender, RoutedEventArgs e) {
    NavigateService.Instance.Navigate(typeof(LoginPage));
}

You will get some errors because you don’t have a SecondPage.xaml and LoginPage.xaml yet.

<Grid>
  <Button Content="Login" Click="ButtonBase_OnClick"   HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Height="100"/>
</Grid>
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
    NavigateService.Instance.Navigate(typeof(MainPage), typeof(MasterPage));
}

Now run your code and you will see that the Login page uses no masterpage and the other pages share Masterpage.xaml.

This is a very basic masterpage navigation system. For our app we extended it with viewmodel injection. If you need help with that, just email me (info@loekvandenouweland.com)!