Navigation via Code Behind

Problem

Navigation logic can often become complex when it has to handle different states and pass data. These situations can lead to decreased readability and reusability.

Solution

Uno Extensions Navigation lets you easily invoke navigation with INavigator through commands defined in the view model, enabling more flexibility and more maintainable code. It is also possible to navigate between pages.

1. NavigateViewModelAsync

This method navigates to a route that matches the specified view model type. Let's say we want to navigate to the search page and display popular recipes. To do so, we can use NavigateViewModelAsync to navigate to the SearchModel and we can add a SearchFilter as data to specify that the recipes should be organized by popularity.

public async ValueTask SearchPopular() =>
    await _navigator.NavigateViewModelAsync<SearchModel>(this, data: new SearchFilter(FilterGroup: FilterGroup.Popular));

2. NavigateDataAsync

This method navigates to a route that is registered for the specified data type. In the root App.xaml.host.cs, since we defined that the GenericDialogModel is registered to a DialogInfo through the DataMap, it will choose the "Dialog" route.

public static Task<NavigationResponse?> ShowDialog(this INavigator navigator, object sender, DialogInfo dialogInfo, CancellationToken ct)
{
    return navigator.NavigateDataAsync(sender, new DialogInfo(dialogInfo.Title, dialogInfo.Content), cancellation: ct);
}
private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
{
    views.Register(
        /* other routes */,
        new ViewMap<GenericDialog, GenericDialogModel>(Data: new DataMap<DialogInfo>())
    );
    
    routes.Register(
        /* other routes */,
        new RouteMap("Dialog", View: views.FindByView<GenericDialog>())
    );
}

3. NavigateBackAsync

This method navigates back to the previous frame on the back-stack.

private async Task NavigateBack()
{
    await _navigator.NavigateBackAsync(this);
}

4. NavigateBackWithResultAsync

This method navigates back to the previous frame on the back-stack with data. Let's say the previous page the user was on was the search page and it was displaying recipes with a certain filter. What if the user navigates to the filter page, changes the search filters, and once submitted is navigated back to the search page? We could use NavigateViewModelAsync but that would mean remaking the SearchModel. That's why we should use NavigateBackWithResultAsync and pass the new filter as data. We can define a DataViewMap to register that the route is expecting a SearchFilter as a parameter when being navigated to.

private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes)
{
    views.Register(
        /* other routes */,
        new DataViewMap<SearchPage, SearchModel, SearchFilter>()
    );
}
public async ValueTask ApplySearchFilter(SearchFilter filter) =>
    await _navigator.NavigateBackWithResultAsync(this, data: filter);

5. NavigateRouteAsync

This method navigates to a registered route, if it exists, without having to specify a view model.

public async ValueTask LiveCooking(IImmutableList<Step> steps, CancellationToken ct)
{
    await _navigator.NavigateRouteAsync(this, "LiveCooking", data: new LiveCookingParameter(Recipe, steps), cancellation: ct);
}

Source Code

Documentation