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
Widgetrecord (or class) for data to be passed between view modelspublic record Widget(string Name, double Weight);Change the
ViewMapinApp.xaml.csthat associates theSecondPageandSecondViewModel, to be aDataViewMapobject that allows you to specify theWidgettype.new DataViewMap<SecondPage, SecondViewModel, Widget>()
2. Pass data when navigating
Create a
Widgetinside theGoToSecondPagemethod inMainViewModel.cs, and pass it asdatainto 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
SecondViewModelconstructor to accept aWidgetparameter.public class SecondViewModel { public string Name { get; } public SecondViewModel(Widget widget) { Name = widget.Name; } }Add a
TextBlocktoSecondPage.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
Widgetand theSecondViewModel(in theViewMapdefined inApp.xaml.cs), an alternative way to navigate is by calling theNavigateDataAsyncand 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
Widgetsproperty to yourMainViewModelpublic Widget[] Widgets { get; } = [ new Widget("NormalSpinner", 5.0), new Widget("HeavySpinner", 50.0) ];Update
MainPage.xamlto replace theButtonwith aListViewwhich has theItemsSourceproperty data bound to theWidgetsproperty. TheNavigation.Requestproperty defines the route that will be navigated to when an item in theListViewis 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.Requestproperty value to"". Navigation will use the type of the selected item to determine what route to use.Add two additional records,
BasicWidgetandAdvancedWidget, 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
Widgetsproperty inMainViewModelto 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.xamlandSecondPage.xaml.csfiles, and rename the files toThirdPage.xamlandThirdPage.xaml.csrespectively. Make sure you also change the class name in both files fromSecondPagetoThirdPage, as well as theContentproperty of theNavigationBarto read "Third Page".Clone
SecondViewModel.csand rename toThirdViewModel.cs. Also rename the class fromSecondViewModeltoThirdViewModelChange the constructor of both the
SecondViewModelandThirdViewModelto 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
DataViewMapandRouteMapforThirdPageandThirdViewModel, specifying theAdvancedWidget. Also, updateDataViewMapforSecondViewModelto beBasicWidgetinstead ofWidgetprivate 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
SecondPageorThirdPagebased on the type of item selected.