How-To: Display Item Details
This topic walks through how to use Navigation to display the details of an item selected from a list. This demonstrates an important aspect of Navigation which is the ability to pass data as part of a 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.
Often it is necessary to pass a data item from one page to another. This scenario will start with passing a newly created object along with the navigation request, and how the specified object can be accessed by the destination ViewModel.
1. Define the type of data to pass
Define a
Widget
record (or class) for data to be passed between view modelspublic record Widget(string Name, double Weight);
Change the
ViewMap
inApp.xaml.cs
that associates theSecondPage
andSecondViewModel
, to be aDataViewMap
object that allows you to specify theWidget
type.new DataViewMap<SecondPage, SecondViewModel, Widget>()
2. Pass data when navigating
Create a
Widget
inside theGoToSecondPage
method inMainViewModel.cs
, and pass it asdata
into the navigation method.public async Task GoToSecondPage() { var widget = new Widget("CrazySpinner", 34.0); await _navigator.NavigateViewModelAsync<SecondViewModel>(this, data: widget); }
3. Receiving navigation data
Update the
SecondViewModel
constructor to accept aWidget
parameter.public class SecondViewModel { public string Name { get; } public SecondViewModel(Widget widget) { Name = widget.Name; } }
Add a
TextBlock
toSecondPage.xaml
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"> <Run Text="Widget Name:" /> <Run Text="{Binding Name}" /> </TextBlock>
4. Navigating with data
Because there's a mapping between the
Widget
and theSecondViewModel
(in theViewMap
defined inApp.xaml.cs
), an alternative way to navigate is by calling theNavigateDataAsync
and specifying the data object to pass in the navigation request. The type of the data object will be used to resolve which route to navigate to.await _navigator.NavigateDataAsync(this, data: widget);
5. Navigating for selected value in a ListView
A common application scenario is to present a list of items, for example presented in a ListView
. When the user selects an item, the application navigates to a new view in order to display the details of that item.
Add a
Widgets
property to yourMainViewModel
public Widget[] Widgets { get; } = [ new Widget("NormalSpinner", 5.0), new Widget("HeavySpinner", 50.0) ];
Update
MainPage.xaml
to replace theButton
with aListView
which has theItemsSource
property data bound to theWidgets
property. TheNavigation.Request
property defines the route that will be navigated to when an item in theListView
is selected.<ListView ItemsSource="{Binding Widgets}" uen:Navigation.Request="Second" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Padding="10"> <TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Age}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>
6. Navigating based on the type of data (again!)
If you have a ListView
that has items of different types, the navigation route can be based on the type of selected item.
Change the
Navigation.Request
property value to""
. Navigation will use the type of the selected item to determine what route to use.Add two additional records,
BasicWidget
andAdvancedWidget
, that derive fromWidget
.public record Widget(string Name, double Weight); public record BasicWidget(string Name, double Weight) : Widget(Name, Weight); public record AdvancedWidget(string Name, double Weight) : Widget(Name, Weight);
Change the
Widgets
property inMainViewModel
to include an array of different types of widgets.public Widget[] Widgets { get; } = [ new BasicWidget("NormalSpinner", 5.0), new AdvancedWidget("HeavySpinner", 50.0) ];
Clone the
SecondPage.xaml
andSecondPage.xaml.cs
files, and rename the files toThirdPage.xaml
andThirdPage.xaml.cs
respectively. Make sure you also change the class name in both files fromSecondPage
toThirdPage
, as well as theContent
property of theNavigationBar
to read "Third Page".Clone
SecondViewModel.cs
and rename toThirdViewModel.cs
. Also rename the class fromSecondViewModel
toThirdViewModel
Change the constructor of both the
SecondViewModel
andThirdViewModel
to accept widgets of different typespublic class SecondViewModel { public string Name { get; } public SecondViewModel(BasicWidget widget) { Name = widget.Name; } } public class ThirdViewModel { public string Name { get; } public ThirdViewModel(AdvancedWidget widget) { Name = widget.Name; } }
Add a
DataViewMap
andRouteMap
forThirdPage
andThirdViewModel
, specifying theAdvancedWidget
. Also, updateDataViewMap
forSecondViewModel
to beBasicWidget
instead ofWidget
private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes) { views.Register( new ViewMap(ViewModel: typeof(ShellViewModel)), new ViewMap<MainPage, MainViewModel>(), new DataViewMap<SecondPage, SecondViewModel, BasicWidget>(), new DataViewMap<ThirdPage, ThirdViewModel, AdvancedWidget>() ); routes.Register( new RouteMap("", View: views.FindByViewModel<ShellViewModel>(), Nested: [ new ("Main", View: views.FindByViewModel<MainViewModel>()), new ("Second", View: views.FindByViewModel<SecondViewModel>()), new ("Third", View: views.FindByViewModel<ThirdViewModel>()), ] ) ); }
Picking an item from the list will either open
SecondPage
orThirdPage
based on the type of item selected.