arrow-left arrow-right brightness-2 chevron-left chevron-right circle-half-full dots-horizontal facebook-box facebook loader magnify menu-down RSS star Twitter twitter GitHub white-balance-sunny window-close
ViewModel-first navigation with Prism
1 min read

ViewModel-first navigation with Prism

This is an old post and doesn't necessarily reflect my current thinking on a topic, and some links or images may not work. The text is preserved here for posterity.

When using Prism, it's common to end up with code like this:

private void ShowHome() 
{
    var view = CreateView();
    var viewModel = CreateViewModel();
    view.DataContext = viewModel;

    var region = regionManager.Regions["SomeRegion"];

    region.Add(view, null, true);
    retion.Activate(view);
}

Using MVVM, we can make the assumption that every view has a view model following a naming convention - HomeView will always have a HomeViewModel.

Here's a shorter way we could write it:

private void ShowHome() 
{
    regionManager.AddViewModel<HomeViewModel>("SomeRegion");
}

The following extension method shows how AddViewModel might be implemented:

public static void AddViewModel<TViewModel>(this IRegionManager regionManager, string regionName)
{
    // Figure out the view based on the ViewModel class 
    var viewTypeName = typeof (TViewModel).FullName.Replace("Model", "View");
    var viewType = typeof (TViewModel).Assembly.GetType(viewTypeName);

    // Build the view and model, and bind them
    var view = (FrameworkElement)ServiceLocator.Current.GetInstance(viewType);
    var model = ServiceLocator.Current.GetInstance<TViewModel>();
    view.DataContext = model;

    // Render
    regionManager.Regions[regionName].Add(view, null, true);
    regionManager.Regions[regionName].Activate(view);
}

The direct reference to ServiceLocator from within the extension method is a code smell, and makes testing a little messy. There are some tricks we could use like wrapping the RegionManager in some kind of object which has a ViewLocator or ViewModelLocator, but you get the picture.

Parameters

To pass parameters to the view model, we could write this:

private void EditCustomer() 
{
    regionManager.AddViewModel<EditCustomerViewModel>("SomeRegion", customerId => 31);
}

Our view model constructor could look like this:

public class EditCustomerViewModel
{
    public EditCustomerViewModel(int customerId, ILogger logger, IFoo foo, IBar bar) 
    {
        ...
    }
}

The other constructor parameters will be resolved by the IOC container, but the customerId is a parameter we'd like to pass manually. At this point, using the service locator isn't enough - it doesn't support parameter passing.

Enjoying these posts? Subscribe for more

Subscribe now
Already have an account? Sign in
Paul Stovell's Blog

Hello, I'm Paul Stovell

I'm a Brisbane-based software developer, and founder of Octopus Deploy, a DevOps automation software company. This is my personal blog where I write about my journey with Octopus and software development.

I write new blog posts about once a month. Subscribe and I'll send you an email when I publish something new.

Subscribe

Comments

You've successfully subscribed to Paul Stovell's Blog.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.