Edit

Share via


Navigate between pages

This portion of the tutorial adds the final piece to the app, navigation between the all notes page and the individual note page.

Before writing any code to handle in-app navigation, let's describe the expected navigation behavior.

In AllNotesPage, there's the collection of existing notes and a New note button.

  • Clicking an existing note should navigate to the note page and load the note that was clicked.
  • Clicking the New note button should navigate to the note page and load an empty, unsaved note.

On the note page, you'll add a back button, and there are Save and Delete buttons .

  • Clicking the back button should navigate back to the all notes page, discarding any changes made to the note.
  • Clicking the Delete button should delete the note and then navigate back.

New note

First, you'll handle navigation for an new note.

Tip

You can download or view the code for this tutorial from the GitHub repo. To see the code as it is in this step, see this commit: navigation - new note.

  1. In AllNotesPage.xaml, find the AppBarButton for a new note.

  2. Add a Click event handler and rename it to NewNoteButton_Click. (See Add event handlers in the note page step if you need a reminder how to do this.)

    <AppBarButton Icon="Add" Label="New note"
                  Click="NewNoteButton_Click"/>
    
  3. In the NewNoteButton_Click method (in AllNotesPage.xaml.cs), add this code:

    private void NewNoteButton_Click(object sender, RoutedEventArgs e)
    {
        // ↓ Add this. ↓
        Frame.Navigate(typeof(NotePage));
    }
    

Each Page has a Frame property that provides a reference to the Frame instance that the Page belongs to (if any). That's the Frame that you call the Navigate method on here. The Navigate method takes the Type of the page that you want to navigate to. You get that Type in C# by using the typeof operator.

If you run the app now, you can click the New note button to navigate to the note page, and you can type into the note editor. However, if you try to save the note, nothing will happen. This is because an instance of the Note model hasn't been created in the note page yet. You'll do that now.

  1. Open NotePage.xaml.cs.

  2. Add code to override the page's OnNavigatedTo method.

    public NotePage()
    {
        this.InitializeComponent();
    }
    //  ↓ Add this. ↓
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        noteModel = new Note();
    }
    

Now, when you navigate to NotePage, a new instance of the Note model is created.

Existing notes

Now you'll add navigation for existing notes. Currently, when you click the note in the ItemsView, the note is selected, but nothing happens. The default behavior for most collection controls is single selection, which means one item is selected at a time. You'll update the ItemsView so that instead of selecting it, you can click an item like a button.

Tip

You can download or view the code for this tutorial from the GitHub repo. To see the code as it is in this step, see this commit: navigation - final app.

  1. Open AllNotesPage.xaml.

  2. Update the XAML for the ItemsView with SelectionMode = None and IsItemInvokedEnabled = True.

  3. Add a handler for the ItemInvoked event.

    <ItemsView ItemsSource="{x:Bind notesModel.Notes}"
               Grid.Row="1" Margin="24" 
               ItemTemplate="{StaticResource NoteItemTemplate}"
               <!-- ↓ Add this. ↓ -->
               SelectionMode="None"
               IsItemInvokedEnabled="True"
               ItemInvoked="ItemsView_ItemInvoked">
    
  4. In AllNotesPage.xaml.cs, find the ItemsView_ItemInvoked method. (If Visual Studio didn't create it for you, which could happen if you copy and paste the code, add it in the next step.)

  5. In the ItemsView_ItemInvoked method, add code to navigate to NotePage. This time, you'll use an overload of the Navigate method that lets you pass an object to the other page. Pass the invoked Note as the second navigation parameter.

    private void ItemsView_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs args)
    {
        Frame.Navigate(typeof(NotePage), args.InvokedItem);
    }
    
  6. Open NotePage.xaml.cs.

  7. Update the OnNavigatedTo method override to handle the Note that's passed by the call to Navigate.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        //  ↓ Update this. ↓
        if (e.Parameter is Note note)
        {
            noteModel = note;
        }
        else
        {
            noteModel = new Note();
        }
       // ↑ Update this. ↑
    }
    

    In this code, you first check to see if the passed parameter is a Note object. If it is, you assign it as the Note model for the page. If it's null or not a Note, create a new Note as before.

Back navigation

Lastly, you need to update the app so that you can navigate back from an individual note to the all notes page.

The WinUI TitleBar control includes a back button that meets all the Fluent Design guidelines for placement and appearance. You'll use this built-in button for back navigation.

  1. Open MainWindow.xaml.

  2. Update the XAML for the TitleBar with IsBackButtonVisible = True and IsBackButtonEnabled bound to the Frame.CanGoBack property.

  3. Add a handler for the BackRequested event. Your XAML should look like this:

    <TitleBar x:Name="AppTitleBar"
              Title="WinUI Notes"
              IsBackButtonVisible="True"
              IsBackButtonEnabled="{x:Bind rootFrame.CanGoBack, Mode=OneWay}"
              BackRequested="AppTitleBar_BackRequested">
    

    Here, the IsBackButtonVisible property is set to true. This makes the back button appear in the upper-left corner of the app window.

    Then, the IsBackButtonEnabled property is bound to the Frame.CanGoBack property, so the back button is enabled only if the frame can navigate back.

    Finally, the BackRequested event handler is added. This is where you put the code to navigate back.

  4. In MainWindow.xaml.cs, add this code to the AppTitleBar_BackRequested method:

    private void AppTitleBar_BackRequested(TitleBar sender, object args)
    {
        // ↓ Add this. ↓
        if (rootFrame.CanGoBack == true)
        {
            rootFrame.GoBack();
        }
        // ↑ Add this. ↑
    }
    

    The Frame class keeps track of navigation in its BackStack, so you can navigate back to previous pages simply by calling the GoBack method. It's a best practice to always check the CanGoBack property before calling GoBack.

Next, you need to update the code in NotePage to navigate back after the note is deleted.

  1. Open NotePage.xaml.cs.

  2. Update the DeleteButton_Click event handler method with a call to the Frame.CanGoBack method after the note is deleted:

    private async void DeleteButton_Click(object sender, RoutedEventArgs e)
    {
        if (noteModel is not null)
        {
            await noteModel.DeleteAsync();
        }
        // ↓ Add this. ↓
        if (Frame.CanGoBack == true)
        {
            Frame.GoBack();
        }
        // ↑ Add this. ↑
    }
    

Tip

You might have noticed that in NotePage, you call Frame.GoBack, while in MainWindow you called rootFrame.GoBack. This is because the Page class has a Frame property that gets the Frame that is hosting the Page, if any. In this case, it gets a reference to rootFrame.

Now you can run your app. Try adding new notes, navigating back and forth between notes, and deleting notes.

Learn more in the docs:

Next steps

Congratulations! You've completed the Create a WinUI app tutorial!

The following links provide more information about creating apps with WinUI and the Windows App SDK: