The Advanced Navigation of Exrin in Xamarin Forms

Exrin is an MVVM framework, with higher levels of abstraction that most other frameworks. It is designed for Xamarin Forms but has no dependency on Xamarin Forms. It certainly pushes its opinions on how your project should be set up, but in doing so gives some very advanced navigation features with relative ease.

Exrin is based on ViewModel navigation. This means you move from ViewModel to ViewModel, not View to View. Every View is bound with a ViewModel, 1 to 1, but the ViewModel is never aware of what View is bound to it. The next diagram is an overview of how Exrin fits together in relation to navigation. It will all be explained below.

exrin

Code Sample: A small sample project Exrin Sample is available if you want to view a working mobile app.

Stacks

Xamarin Forms has a NavigationStack and a ModalStack. Exrin never uses the ModalStack, only the NavigationStack. Exrin creates its own stacks. Whenever you want to switch Stacks, it changes the MainPage to the next stack and allows you to switch back to the previous stack, right where you left off.

The common example I use with this is AuthenticationStack and MainStack. You don’t want the user to be able to use back navigation to reach the login page again. Its part of a different page flow and should be kept separate. Its really simple to create stacks, you set the start page and the map the Views to the ViewModels.

// Authentication is just an enum used to keep a track of the views. This is the ViewKey.

protected override void Map()
{
    base.NavigationMap<LoginView, LoginViewModel>(nameof(Authentication.Login));
}

public override string NavigationStartKey
{
    get
    {
        return nameof(Authentication.Login);
    }
}

NoHistory & View Caching

Before we move on I wanted to point out a small feature that allows you to cache the view, so it doesn’t have to be rebuilt each time you view it. NoHistory is great feature that you can tag any View-ViewModel mapping with. When this is set to true, once another view is pushed over the top of this one, or the stack is changed, this View will be silently popped. When you go back it will no longer be in the Navigation History.

base.NavigationMap<SplashView, SplashViewModel>(nameof(Authentication.Splash), new MapOptions() { NoHistory = true });

ViewModel Overrides

One of the big benefits of Exrin is the amount of overrides you get in each ViewModel to allow you to start or finish tasks at any stage in the navigation process.

// This View is about to be navigated to. Do anything before the View is pushed to the stack and made visible.
// Will wait for this to return before the View is pushed to the stack.
public override Task OnPreNavigate(object args)
{
// When this View is displayed again because the page on top of it was popped from the stack
public override Task OnBackNavigated(object args)
{
// When the page has been navigated to
public override Task OnNavigated(object args)
{
// When the View this is mapped to is popped from the Navigation Stack.
public override void OnPopped()
{
// When the View this is mapped to has its OnAppearing event called
public override void OnAppearing()
{
// When the View this is mapped to has the disappearing event called
public override void OnDisappearing()
{
// When the hardware back button is pressed
public override bool OnBackButtonPressed()
{

Navigation

Navigation in Exrin is actually done using the Operation Separation approach. You just return a result from the Operation in the ViewModel and Exrin handles the rest. A quick example below shows a navigation result. It is going to the Main Stack and the Main View on that stack. Main is the just the name of a View in that stack.

new Result() { ResultAction = ResultType.Navigation, Arguments = new NavigationArgs() { Key = Main.Main, StackType = Stack.Main } };

You are open to interact with the NavigationService directly, by injecting the INavigationService. The NavigationService has the following definition.

Task Navigate(string key);

Task Navigate(string key, object args);

Task Navigate(object stackIdentifier, string key, object args);

Task Navigate(string key, object args, IStackOptions options);

StackResult Navigate(IStackOptions options);

The Key is the key you assigned to the View in a stack. StackIdentifier is the key you assigned to the stack. If you don’t give a StackIdentifier it assumes you mean the same stack. Args is an object that contains anything you want to pass to the ViewModel.

Exrin takes care of switching stack and popping or pushing views to reach your target, you don’t need to know how to get to a page and stack, just enter in your intended target.

IStackOptions is for switching stacks and navigating to a page but offers more flexibility in what it can do. For example, if you wish to switch to a Stack, don’t know what View its currently on but don’t want to change it, you can just send through the StackChoice, which is actually the StackIdentifier (apologies on the inconsistent naming, I might have to issue a breaking change for that down the track).

You also have the ability to load a Stack with a number of views preloaded. If you want to jump to a view in a Stack but need a few views loaded first, then you can use the PreDefinedStack to list them. They will be loaded in the Stack before your ViewKey. This happens in the background, your user will not see flickering pages.

public interface IStackOptions
{
    object StackChoice { get; }

    string ViewKey { get; set; }

    object Args { get; }

    /// <summary>
    /// An ordered array with the Page Keys for a stack to be preloaded.The last page on the array will be the visible one.
    /// </summary>
    IDictionary<string, object> PredefinedStack { get; }

    /// <summary>
    /// If the ArgsKey is blank pass the args through. Otherwise the ArgsKey must match the ViewKey being loaded for the args to be passed.
    /// </summary>
    string ArgsKey { get; }
}

View Container

The last concept I am introducing is the View Hierarchy, designed specifically for more complex views such as MasterDetailPage and TabbedPage. You place a Stack in a ViewContainer. In the case of TabbedPages and MasterDetailPages you place multiple stacks in the container.

When you navigate you still select which Stack and page you navigate to. Exrin handles the rest and shows the correct view.

These views are a little more complex but you can look at my Tesla Example to see a MasterDetailPage and TabbedPage in action.

Microsoft MVP (Xamarin) | Exrin | Xamarin Forms Developer | Melbourne, Australia | Open to sponsorship to Canada or US

Related Posts

Leave A Comment?