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.xamlAdd a new class,
SampleViewModel, to the class library projectpublic class SampleViewModel { public SampleViewModel(INavigator navigator) { _navigator = navigator; } private readonly INavigator _navigator; }In
MainPage.xamlupdate theButtonto use theNavigation.Requestattached property instead of theClickevent 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 thePageelement with<Page x:Class="NavigateInXAML.Views.SamplePage" ... xmlns:uen="using:Uno.Extensions.Navigation.UI">In
SamplePage.xamladd aButton, again with theNavigation.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 defineViewMapandRouteMapAdd a
ViewMapand aRouteMapfor theSamplePageinto theRegisterRoutesmethod in theApp.xaml.csfileprivate 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, toMainViewModelthat returns an array of predefinedWidgetinstances.public Widget[] Widgets { get; } = [ new Widget("NormalSpinner", 5.0), new Widget("HeavySpinner", 50.0) ];Replace the
Buttonwith aListViewinMainPage.xamlthat has theItemsSourceproperty data bound to theWidgetsproperty.<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 theStackPanelonMainPage.xamlthat has bothNavigation.Request, that specified the navigation route, and theNavigation.Dataproperties. In this case theNavigation.Dataattached property is data bound to theSelectedItemproperty on the named elementWidgetsList(which matches thex:Nameset on the previously addedListView)<Button Content="Go to Sample Page" uen:Navigation.Request="Sample" uen:Navigation.Data="{Binding SelectedItem, ElementName=WidgetsList}"/>Update
SecondViewModelto accept aWidgetas the second constructor parameterpublic class SampleViewModel { public string Title => "Sample Page"; public string Name { get; } public SampleViewModel(Widget widget) { Name = widget.Name; } }Add a
TextBlocktoSecondPage.xamlthat shows the name of theWidgetsupplied during navigation.<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"> <Run Text="Widget Name:" /> <Run Text="{Binding Name}" /> </TextBlock>In order for the
Widgetto be injected into theSampleViewModelduring navigation, aDataMaphas to be added to theViewMap. Therefore, we can change theViewMapinstantiation toDataViewMapand provide theWidgetas 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 theListView. TheNavigation.Dataproperty is not required as the selected item will automatically be attached to the navigation request. Also remove theSelectionModeproperty as it is no longer necessary for theListViewto 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>