Prism. Auto-register your views/ pages

This is quick blog post and I want to share with you how I solve a recurrent issue working with Prism and MVVM in a Xamarin Forms project. I’ve working on several teams and projects for years and it’s common to forget register a new Page (we’re humans), or even worst, loose it in a git merge because the conflict is not resolve properly (i.e. team members including new features at the same time).

At least in my projects all the Views/ ViewModels are registered in the same way.

I know that the Prism guys (Brian Lagunas, Dan Siegel) have include a new attribute to auto register the Views. This new attribute was included in the version 7.2.0.1367 and the name is AutoRegisterForNavigation. IMHO it’s a good choise but it’s not my preferred one because the attributes usually are hidden (a little bit) in the code and if the team is not a mature one maybe it’s hard to find it or to tell what the magic happens.

I usually create two extension methods of IContainerRegistry, one to register my services and another one to register my Views/ ViewModels in order to clear my App.xaml.cs file. I really hate having too much code here.

public partial class App : PrismApplication
{
    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterServices();
        containerRegistry.RegisterPages();
    }
}

public static class ContainerRegistryExtensions
{
    public static void RegisterServices(this IContainerRegistry containerRegistry)
    {
        containerRegistry.Register<ISalesService, SalesService>();
    }

    public static void RegisterPages(this IContainerRegistry containerRegistry)
    {
        containerRegistry.RegiterForNavigation<SalesView>();
    }
}

It’s clear to auto-register your pages you have to use reflection and I usually like to use a marker interface instead of use a type so with a single marker interface we can do it.

//This is the marker interface
public interface IRegisterablePage
{
}

And every page or even better, your View/ Page base class has to implement the marker interface.

//Could be your view/ page base class
public partial class OrdersView : ContentPage, IRegisterablePage
{
    public OrdersView()
    {
        InitializeComponent();
    }
}

And the code to register your Views/ Pages now is:

public static void RegisterPages(this IContainerRegistry containerRegistry)
{
    //Register any page that have not implement the marker interface
    containerRegistry.RegisterForNavigation<NavigationPage>();

    //Auto-register the Views/ Pages
    var pages = GetClasses<IRegisterablePage>();
    foreach (var page in pages)
    {
        containerRegistry.RegisterForNavigation(page, page.Name);
    }
}

private static IEnumerable<Type> GetClasses<T>()
{
    return AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(s => s.GetTypes())
        .Where(p => p.IsClass && typeof(T).IsAssignableFrom(p));
}