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.
Step-by-steps
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 instructions for creating 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, where as the SelectionChanged
event on a ListView
is used. If you place a Navigation.Request
property on an static element, such as a Border
, Image
or TextBlock
, the Tapped
event will be used to trigger navigation.
Add a new
Page
to navigate to,SamplePage.xaml
, in the UI (shared) projectAdd a new class,
SampleViewModel
, to the class library projectpublic class SampleViewModel { public SampleViewModel(INavigator navigator) { _navigator = navigator; } private readonly INavigator _navigator; }
In
MainPage.xaml
update theButton
to use theNavigation.Request
attached property instead of theClick
event handler.<Button Content="Go to SamplePage" uen:Navigation.Request="Sample" />
Tip
As Navigation.Request attached property exists in the Uno.Extensions.Navigation.UI
namespace you will need to import this namespace on the Page
element with
<Page x:Class="NavigateInXAML.Views.SamplePage"
...
xmlns:uen="using:Uno.Extensions.Navigation.UI">
In
SamplePage.xaml
add aButton
, again with theNavigation.Request
attached property. The "-" navigation route is used to navigate back.<Button Content="Go Back" uen:Navigation.Request="-" />
Tip
Whilst this works, it relies on reflection to convert the request path "Sample" to the corresponding view, i.e. SamplePage
. It's better to define ViewMap
and RouteMap
Add a
ViewMap
and aRouteMap
for theSamplePage
into theRegisterRoutes
method in theApp.xaml.host.cs
fileprivate static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes) { views.Register( new ViewMap<ShellControl,ShellViewModel>(), new ViewMap<MainPage, MainViewModel>(), new ViewMap<SecondPage, SecondViewModel>(), new ViewMap<SamplePage, SampleViewModel>() ); routes.Register( new RouteMap("", View: views.FindByViewModel<ShellViewModel>() , Nested: new RouteMap[] { new RouteMap("Main", View: views.FindByViewModel<MainViewModel>()), new RouteMap("Second", View: views.FindByViewModel<SecondViewModel>()), new RouteMap("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
, toMainViewModel
that returns an array of predefinedWidget
instances.public Widget[] Widgets { get; } = new[] { new Widget("NormalSpinner", 5.0), new Widget("HeavySpinner",50.0) };
Replace the
Button
with aListView
inMainPage.xaml
that has theItemsSource
property data bound to theWidgets
property.<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
Button
to theStackPanel
onMainPage.xaml
that has bothNavigation.Request
, that specified the navigation route, and theNavigation.Data
properties. In this case theNavigation.Data
attached property is data bound to theSelectedItem
property on the named elementWidgetsList
(which matches thex:Name
set on the previously addedListView
)<Button Content="Go to Sample Page" uen:Navigation.Request="Sample" uen:Navigation.Data="{Binding SelectedItem, ElementName=WidgetsList}"/>
Update
SecondViewModel
to accept aWidget
as the second constructor parameterpublic class SampleViewModel { public string Title => "Sample Page"; public string Name { get; } public SampleViewModel(Widget widget) { Name = widget.Name; } }
Add a
TextBlock
toSecondPage.xaml
that shows the name of theWidget
supplied during navigation.<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"> <Run Text="Widget Name:" /> <Run Text="{Binding Name}" /> </TextBlock>
In order for the
Widget
to be injected into theSampleViewModel
during navigation, aDataMap
has to be added to theViewMap
new ViewMap<SamplePage, SampleViewModel>(Data: new DataMap<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.Request
property to theListView
. TheNavigation.Data
property is not required as the selected item will automatically be attached to the navigation request. Also remove theSelectionMode
property as it is no longer necessary for theListView
to 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>