How-To: Navigate in XAML
This topic walks through controlling Navigation from XAML. This includes specifying data that should be attached to the navigation request.
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. Navigation.Request
Navigation can be defined in XAML by placing the Navigation.Request attached property on a specific XAML element. The string value specified in the Navigation.Request is the route to be navigated to.
Depending on the type of the XAML element, the Navigation.Request property will attach to an appropriate event in order to trigger navigation. For example, on a Button, the Click event will be used to trigger navigation, whereas the SelectionChanged event on a ListView is used. If you place a Navigation.Request property on a static element, such as a Border, Image, or TextBlock, the Tapped event will be used to trigger navigation.
- Add a new - Pageto navigate to,- SamplePage.xaml
- Add a new class, - SampleViewModel, to the class library project- public class SampleViewModel { public SampleViewModel(INavigator navigator) { _navigator = navigator; } private readonly INavigator _navigator; }
- In - MainPage.xamlupdate the- Buttonto use the- Navigation.Requestattached property instead of the- Clickevent handler.- <Button Content="Go to SamplePage" uen:Navigation.Request="Sample" />- Tip- As Navigation.Request attached property exists in the - Uno.Extensions.Navigation.UInamespace you will need to import this namespace on the- Pageelement with- <Page x:Class="NavigateInXAML.Views.SamplePage" ... xmlns:uen="using:Uno.Extensions.Navigation.UI">
- In - SamplePage.xamladd a- Button, again with the- Navigation.Requestattached property. The "-" navigation route is used to navigate back.- <Button Content="Go Back" uen:Navigation.Request="-" />- Tip- While this works, it relies on reflection to convert the request path "Sample" to the corresponding view, i.e. - SamplePage. It's better to define- ViewMapand- RouteMap
- Add a - ViewMapand a- RouteMapfor the- SamplePageinto the- RegisterRoutesmethod in the- App.xaml.csfile- 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>()), ] ) ); }
2. Navigation.Data
In addition to specifying the route to navigate to, the Navigation.Data attached property can be used to define the data to be attached to the navigation request. The data can be accessed by the view model associated with the route using constructor injection.
- Define a record (or class), - Widget, that is the type of data that will be attached to the navigation request.- public record Widget(string Name, double Weight);
- Add a property, - Widgets, to- MainViewModelthat returns an array of predefined- Widgetinstances.- public Widget[] Widgets { get; } = [ new Widget("NormalSpinner", 5.0), new Widget("HeavySpinner", 50.0) ];
- Replace the - Buttonwith a- ListViewin- MainPage.xamlthat has the- ItemsSourceproperty data bound to the- Widgetsproperty.- <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"> <ListView ItemsSource="{Binding Widgets}" x:Name="WidgetsList" SelectionMode="Single"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Padding="10"> <TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Age}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackPanel>
- Add a - Buttonto the- StackPanelon- MainPage.xamlthat has both- Navigation.Request, that specified the navigation route, and the- Navigation.Dataproperties. In this case the- Navigation.Dataattached property is data bound to the- SelectedItemproperty on the named element- WidgetsList(which matches the- x:Nameset on the previously added- ListView)- <Button Content="Go to Sample Page" uen:Navigation.Request="Sample" uen:Navigation.Data="{Binding SelectedItem, ElementName=WidgetsList}"/>
- Update - SecondViewModelto accept a- Widgetas the second constructor parameter- public class SampleViewModel { public string Title => "Sample Page"; public string Name { get; } public SampleViewModel(Widget widget) { Name = widget.Name; } }
- Add a - TextBlockto- SecondPage.xamlthat shows the name of the- Widgetsupplied during navigation.- <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"> <Run Text="Widget Name:" /> <Run Text="{Binding Name}" /> </TextBlock>
- In order for the - Widgetto be injected into the- SampleViewModelduring navigation, a- DataMaphas to be added to the- ViewMap. Therefore, we can change the- ViewMapinstantiation to- DataViewMapand provide the- Widgetas a generic argument:- new DataViewMap<SamplePage, SampleViewModel, Widget>()
3. Navigating To SelectedItem
Instead of having to select an item in the ListView and then clicking on the Button, Navigation can be triggered when the user selects an item in the ListView.
- Add the - Navigation.Requestproperty to the- ListView. The- Navigation.Dataproperty is not required as the selected item will automatically be attached to the navigation request. Also remove the- SelectionModeproperty as it is no longer necessary for the- ListViewto track the selected item.- <ListView ItemsSource="{Binding Widgets}" uen:Navigation.Request="Sample"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Padding="10"> <TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Age}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>