How-To: Navigate in Code
This topic walks through controlling Navigation from code, either in the code-behind file of a Page or in the corresponding view model. One of the Navigation objectives was a single navigation construct that applies wherever you choose to write your navigation code.
Note
This guide uses predefined code created by the Uno Template using the Recommended
preset, however, it uses the MVVM
approach for the examples instead of MVUX
defined in the Recommended
preset.
Step-by-step
Important
This guide assumes you used the template wizard or dotnet new unoapp
to create your solution. If not, it is recommended that you follow the Creating an application with Uno.Extensions documentation to create an application from the template.
1. Navigating to a New Page
Navigation can be invoked in the code-behind file of a Page
by using the Navigator
extension method to get an INavigator
instance.
Add a new
Page
to navigate to,SamplePage.xaml
In
MainPage.xaml
update theButton
to the following XAML, which includes a handler for theClick
event<Button Content="Go to SamplePage" Click="GoToSamplePageClick" />
In the
GoToSamplePageClick
method, use theNavigator
extension method to get a reference to anINavigator
instance and callNavigateViewAsync
to navigate to theSamplePage
. This will push a new instance of theSamplePage
onto the current frame, pushing theMainPage
to the back-stack.private void GoToSamplePageClick(object sender, RoutedEventArgs e) { _ = this.Navigator()?.NavigateViewAsync<SamplePage>(this); }
2. Navigating Back to the Previous Page
In
SamplePage.xaml
add aButton
with a handler for theClick
event<Button Content="Go Back" Click="GoBackClick" />
Again, use the
Navigator
extension method to access theINavigator
instance and callNavigateBackAsync
. This will cause the frame to navigate to the previous page on the back-stack and releasing theSamplePage
instance.private void GoBackClick(object sender, RoutedEventArgs e) { _ = this.Navigator()?.NavigateBackAsync(this); }
3. Navigate to a ViewModel
The NavigateViewAsync
method uses the type of the view, i.e. SamplePage
, to determine the view to navigate to. By associating a view model with a view, Navigation can be defined based on the type of view model to navigate to. This means that the Navigation logic isn't dependent on the UI layer of the application. The Navigation logic can then be moved into a view model and thus making it easier to test.
Create a new class
SampleViewModel
in theViewModels
folder of the class library projectpublic class SampleViewModel { public SampleViewModel() { } }
Add
ViewMap
andRouteMap
instances in theRegisterRoutes
method inApp.xaml.cs
. This associates theSampleViewModel
with theSamplePage
, as well as avoiding the use of reflection for route discovery.private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes) { views.Register( new ViewMap(ViewModel: typeof(ShellViewModel)), new ViewMap<MainPage, MainViewModel>(), new DataViewMap<SecondPage, SecondViewModel, Entity>(), new ViewMap<SamplePage, SampleViewModel>() ); routes.Register( new RouteMap("", View: views.FindByViewModel<ShellViewModel>(), Nested: [ new ("Main", View: views.FindByViewModel<MainViewModel>()), new ("Second", View: views.FindByViewModel<SecondViewModel>()), new ("Sample", View: views.FindByViewModel<SampleViewModel>()), ] ) ); }
Now that there's an association between
SamplePage
andSampleViewModel
the code inMainPage.xaml.cs
can be updated to use theNavigateViewModelAsync
method.private void GoToSamplePageClick(object sender, RoutedEventArgs e) { _ = this.Navigator()?.NavigateViewModelAsync<SampleViewModel>(this); }
4. View Model Navigation
The logic for navigating back from
SamplePage
toMainPage
can be moved into theSampleViewModel
. Add theGoBack
method toSampleViewModel
that uses theINavigator
instance that's injected via the constructor.public SampleViewModel(INavigator navigator) { _navigator = navigator; } public Task GoBack() { return _navigator.NavigateBackAsync(this); } private readonly INavigator _navigator;
During Navigation from
MainPage
toSamplePage
an instance of theSampleViewModel
will get created and assigned as theDataContext
of the newly createdSamplePage
. In order tox:Bind
to properties and methods on theSampleViewModel
, expose aViewModel
property that returns theDataContext
property as aSampleViewModel
.public SampleViewModel? ViewModel => DataContext as SampleViewModel; public SamplePage() { this.InitializeComponent(); }
Update the
Button
inSamplePage.xaml
to usex:Bind
to define the event handler for theClick
event.<Button Content="Go Back (View Model)" Click="{x:Bind ViewModel.GoBack}" />
Tip
The logic to navigate from MainPage
to SamplePage
can also be refactored into the MainViewModel
. Irrespective of whether the logic is in the code-behind or in the view model, it would use the same NavigateViewModelAsync<SampleViewModel>
method call.
There are many other extension methods on the INavigator
interface that can be used from either the code-behind or view model. Here are a few of the key navigation methods:
NavigateRouteAsync - Navigates to a route specified as a string
NavigateViewAsync - Navigates to a route that matches the view type specified
NavigateViewModelAsync - Navigates to a route that matches the view model type specified
NavigateDataAsync - Navigates to a route that is registered for the data type specified
NavigateForResultAsync - Navigates to a route that is registered to return the result data type specified