WinUI 3.0 Desktop - C# Page Navigation

Viewed 4498

I am trying to do a simple page navigation but I am unable to find any documentation on how to do so in WinUI 3.0.

Currently, when I create a Blank App using WinUI 3.0, I get the following code created in App.xaml.cs

    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        m_window = new MainWindow();
        m_window.Activate();
    }

    private Window m_window;

While in many other examples I've found on the web, a root frame is defined in the OnLaunched event above.

How am I to define MainWindow.xaml or App.xaml such that I can get a frame where I can freely switch between Page1.xaml and Page2.xaml?

Edit: I've now found out that I can retrieve the frame by calling:

    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        m_window = new MainWindow();
        Frame rootFrame = m_window.Content as Frame;
        m_window.Activate();
        rootFrame.Navigate(typeof(UI.MainMenu));
    }

But Navigate fails with a System.NullReferenceException: 'Object reference not set to an instance of an object.' error. What am I doing wrong :S?

2 Answers

Probably the best way is to create a Frame object and assign it to m_window, rather than have a dedicated XAML window. I think you can simply do this:

this.m_window = new Window();
this.m_window.Content = rootFrame = new Frame(); ;
this.m_window.Activate();
rootFrame.Navigate(typeof(MainPage));

You'll need to rename the MainWindow to MainPage and change it's root element type to Page.

In your App class, you can expose a public Navigate method that delegates to the rootFrame's Navigate. In so doing, you will be able to use App.Current to get the app instance from anywhere in your app, thus causing your app's root frame to navigate forward in the back stack.

Alternatively, make a Prism-like navigation service to provide navigation services throughout the app.

So, I managed to find a way to do this.

First, I created a window that I will be referring to as the NavigationRootWindow.

<Window
x:Class="StackOverflow.UI.NavigationRootWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:StackOverflow.UI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid>
    <Frame x:Name="rootFrame"/>
</Grid>

In here, I added a frame that I named rootFrame.

Now, in the App I define the onLaunched function as is autogenerated, but I make sure that the window that is added, is the root window:

    protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
    {
        m_window = new UI.NavigationRootWindow();
        m_window.Activate();
    }

    private Window m_window;

Now, in the cs file of the NavigationRootWindow, I can navigate to the page file that I want:

public sealed partial class NavigationRootWindow : Window
{
    public NavigationRootWindow()
    {
        this.InitializeComponent();

        rootFrame.Navigate(typeof(MainMenu));
    }
}

Where MainMenu is a page element :) Now, in a page element, you can just call this.Frame to get the current frame - which allows you to navigate to another page and even back and forth. An example:

    private void ConnectButton_OnClick(object sender, RoutedEventArgs e)
    {
        this.Frame.Navigate(typeof(SecondMenu));
    }

I'm not certain that this is best practice, but it indeed works :D

Related