Click here to Skip to main content
15,867,330 members
Articles / Desktop Programming / WPF

ViewModel 1st Child Container PRISM Navigation

Rate me:
Please Sign up or sign in to vote.
5.00/5 (17 votes)
20 Aug 2013CPOL11 min read 49.9K   1K   30   13
Shows how to use PRISM navigation API in VM 1st with child container support
Here is a link where you can download the  Demo Application

Introduction

I recently had the good fortune to be able to start a green field  project (literally from scratch). The only criteria I had was that it must be  done in WPF, as that is what the rest of the deployable UIs are using, and  it's also what the rest of the developers at the company know how to use. So WPF fair  enough I like that stuff. So if I am doing a new WPF application what sort of  things would I look to do, and how?

Here is my must have list:

  • Composable UI (either using DataTemplates or some sort of view resolution technique)
  • Full IOC support for every aspect of the application
  • Some form of modularity
  • Extensibility

Mmmm that sounds an aweful lot like the composite guidance for WPF : PRISM.  Yeah you caught me, this article will in fact be about PRISM,  where I will be discussing some alternative approaches to working with PRISM  around the first 2 points in the list above. One thing you should know right  now, is that this article is quite a niche article in a  lot of ways, as it is not a golden bullet that you could just apply everywhere,  it does however work very well in th correct scenario. That said if you use PRISM  / want to use PRISM  this may be of use to you.

Just for completeness what I typically do on any new WPF project, is pull in  bits and pieces from all over the place, which lately looks a bit like this:

  • PRISM  for its regions/IOC support/modularity (oh by the way when I say PRISM  I mean PRISM 4 / 4.1)
  • Cinch for some of my  helper classes
  • Rx for doing async coding  / streams
  • Stuff from a personal library containing all sorts of disparate stuff

 

The Demo App Overview

As I stated previously I will be concentrating on the following 2 areas of  working with PRISM

  • Composable UI (either using DataTemplates or some sort of view resolution technique)
  • Full IOC support for every aspect of the application

The demo application on the surface of it is a simple demonstration of PRISMs  region functionality, specifically a TabControl selector region adaptor (which comes with PRISM  out of the box)

The demo application looks like this, not very exciting, I give you that.

Image 1

YOU CAN CLICK THE IMAGE FOR A BIGGER VERSION

In fact this looks very dull, but read on, we will get some value out of this  article if it kills me.

 

View Model First With PRISM

When developing XAML based applications you are either in the ViewModel first  camp, or the View first camp. Apparently designers love working with View first  and VisualState(s) rather than DataTemplates. Thing is PRISM  sorta/kinda (out of the box) forces your hand towards a more View first approach  where you must either

  • Add a View to a region
  • Navigate to a View within a region

Now that may seem reasonable enough, BUT and its a  big one, have any of you actually worked with a designer (in fact have any of  you ever seen one of these mythical XAML designer people, do they exist, they  seem rarer than an abominable snowman, like I say I have only ever met one)  on a XAML project that  really knew their XAML and also knew Expression Blend inside out.

I have (but only  once), and guess what........they DID NOT work with a View first  appraoch, but they did like VisualState(s), which you can use  anywhere actually. You basically have to pick Triggers (Sliverlight doesn't  support these anyway) or VisualState(s). I think given the choice  designers would always go for VisualState(s) anyway.

They DID however work pretty much  exclusively in DataTemplates. Now I am not talking an average  designer, they were good and definately knew their onions, and it was a complex  XAML based product, with literally 500,000 lines of code. It was big.

This assured me of 2 things:

  1. You can go ViewModel first, which is what developers love and want to  use
  2. You can still use VisualState(s) which is what designers love and want  to use. In fact this has little to do with VM first or View first, I just  wanted to assure people that just because you went for a VM first approach,  you should still be able to keep your designer folk happy.

Kind of like having your cake and eating it.....Mmmmm....tell me more you  say.

Thing is, in the opening gambit of this section I stated that "PRISM  sorta/kinda (out of the box) forces your hand towards a more View first approach".  This is sorta/kinda true, in that every bit of documentation you will likely find on  using PRISM and  its region support and its navigation API will talk about a View first approach.

However hidden away in the documentation, and within a single awesome line  (literally 1 line, blink and you would miss it) within the PRISM  book/docs is a mechanism that you can use to do ViewModel first navigation using PRISMs  navigation API. Awesome.

It essentially looks like this when you register a "ViewModel" for navigation  within the IOC container (I am using Unity here, but for MEF it is even easier  as you can just use the ViewModels full name as the export contract value) :

C#
Container.RegisterTypeForNavigation<MainContainerDummyViewModel>();

Which makes use of the following simple extension method that I have written,  which helps to make the IOC registration process a little simpler and less  cluttered.

C#
public static void RegisterTypeForNavigation<T>(this IUnityContainer container)
{
    container.RegisterType(typeof(Object), typeof(T), typeof(T).FullName);
}
IMPORTANT :

When using the Unity container the registering against the
typeof(Object)
is a vital part of the  registration. If you do not do it exactly like this, you will likely  just get the ViewModel name shown as a string representation rather that  the actual ViewModel that you hope to apply a DataTemplate to.

Now that we have a mechanism for registering a ViewModel for navigtion within  the Unity IOC container, we might show a ViewModel within a region like this:

C#
private void NavigateToMainContainerViewModel(CreateMainContainerViewModelMessage message)
{
    UriQuery parameters = new UriQuery();
    parameters.Add("ID", mainContainerCounter++.ToString());


    var uri = new Uri(typeof(MainContainerDummyViewModel).FullName + parameters, UriKind.RelativeOrAbsolute);
    regionManager.RequestNavigate("MainRegion", uri, HandleNavigationCallback);
}

This actually works just fine. Like I say PRISM  does support ViewModel fisrt, it is just not that well known or publicised.  Thing is once you know it, its easy to do.

 

How Can We Structure Things A Bit Better

Ok so where are we, we now know that we can indeed actually support a ViewModel  first approach using PRISM,  which keeps us developers happy. And as I say when I was actually working with  one of these mythical designers that knows XAML/Blend (rather than PhotoShop)  they were just fine working with DataTemplates and the thing they  like A.K.A the VisualState(s).

Thing is if you can imagine a medium to large scale project with 100nds of  ViewModel and possibly 1000nds of UI Services (at one place I worked they had  this), it is not so hard to imagine that having a single application IOC  container, and having to carefully think out all the component life cycles that  are registered within the container would soon become:

  • Fairly overwhelming : as you would have to really really understand how  and when each component was to be used. Could you really know exactly when  something that makes use of an IOC registered component will be used and  released. This is kind of down to how the users will use the system I feel
  • Poorly structured : due to there being only one container that shared  all the component regisitrations (ok this would likely be done across  serveral modules in PRISM,  but the underlying issue is the same, there is only 1 container)
  • Maintenance nightmare : for obvious reasons
  • Would likely be fairly brittle : as you may not fully understand the  proper life cycles of your IOC components, as they may be shared between  ViewModels that come in and out of existence. What life time management  would you use. Singleton? Shared?

My personal feeling is a lot of these issues can be solved by using child  containers. Now PRISM  ships with support for Unity and MEF, but some of the work by the community has  allowed you to plug in other IOC containers into PRISM.  For this article I am using Unity as it does the job well enough and I like its  support for child containers. I have not really used the child container  approach with MEF so can't comment on it really. Certainly the approach I am  about to discuss here would work just fine with Castle Windsor say.

Now I am not saying that having a child container is the answer to every WPF  issue you will come across, as I have stated already, it is very niche, I totally get that. The areas in which it would work  very well are things like

  • Some sort of Tabbed interface, where each tab could be a ViewModel and  the Tab could be closeable
  • Some sort of workspace interface where you may have small portions of the UI  represented by closeable viewmodels

Essentially anywhere, where you will be on control of calling Dispose() on  the ViewModel in response to some user action (such as a Tab close, or  closing/removing a ViewModel) might benefit from using a child container.

A typical arrangement that I would go for when using PRISM  in this way might be something like this:

Image 2

So that is the general idea, let's now have a look at some code.

Make sure we can create a child container registration for use with PRISM.  As before I have created a simple extension method to make this work as easy as  possible

C#
public static void RegisterTypeForNavigationWithChildContainer<T>(this IUnityContainer container)
{
    container.RegisterType(typeof(Object), typeof(T), typeof(T).FullName, 
        new InjectionMethod("AddDisposable", new object[] { container }));
}

It can be seen this code is much the same as the previous Unity registration  code, there is however one new thing of note here. Which is that the child  container is being passed to an AddDisposable method, lets have a  look at that. The idea being that when the ViewModel is disposed either  programatically or via GC the child container and all its registered components  would also be disposed. As I say it will not work for every thing, but for  closeable ViewModel (think Tabbed UI) / workspace type UI designs it works very  well.

NOTE : I am making use of Reactive Extensions here, but that is just beacuse  I decided to make my Event Aggregator using Rx, but the

CompositeDisposable
which you see below could easily be swapped for a List<IDisposable> should you not want to use Rx.

C#
public abstract class DisposableViewModel : INPCBase, IDisposable
{
    CompositeDisposable disposables = new CompositeDisposable();


    public void AddDisposable(IDisposable disposable)
    {
        disposables.Add(disposable);
    }

    public void Dispose()
    {
        foreach (var disposable in disposables)
        {
            disposable.Dispose(); 
        } 
    }
}

 

So let's now see how we deal with creating a new ViewModel and showing it  using PRISM and  also how to tie the lifetime of the child container to the ViewModel. As I say this  will not suite everyone, it is a very niche requirement, but one that I  personally have found extremely useful.

C#
/// <summary>
/// Creates a child container for a viewmodel and registers its dependencies and then shows the ViewModel. It
/// also ties the lifetime of the child container to that of the newly instantatied ViewModel.
/// </summary>
/// <param name="message">The message that has been seen to create a new ViewModel to show</param>
private void NavigateToChildContainerViewModel(CreateChildContainerViewModelMessage message)
{
    var childcontainer = mainAppContainer.CreateChildContainer();

    //note if you want to have services that are disposable that you want disposed when child container is disposed
    //they need to be registered using the "HierarchicalLifetimeManager"
    childcontainer.RegisterType<ISomeDummyDisposableService, SomeDummyDisposableService>(new HierarchicalLifetimeManager());

    //this is how to use ViewModel 1st Unity registration
    childcontainer.RegisterTypeForNavigationWithChildContainer<ChildContainerDummyViewModel>();

    UriQuery parameters = new UriQuery();
    parameters.Add("ID", childContainerCounter++.ToString());

    var uri = new Uri(typeof(ChildContainerDummyViewModel).FullName + parameters, UriKind.RelativeOrAbsolute);

    //use the custom extension methods to specify our own container to use
    regionManager.RequestNavigateUsingSpecificContainer("MainRegion", uri, HandleNavigationCallback, childcontainer);
}

 

Supporting Child Containers For Our PRISM Regions

In order to get PRISM  to support child containers all the way down to where it creates the actual item  to show within the region that the navigation API is working with,  I had to  change a few things around a bit. This is one of the things I really like about PRISM  is that IT IS TOTALLY EXTENSIBLE.

I started with this extension method

C#
public static class RegionExtensions
{
    public static void RequestNavigateUsingSpecificContainer(this IRegion region, 
        Uri target, Action<NavigationResult> navigationCallback, 
        IUnityContainer containerToUse)
    {
        CustomRegionNavigationService moneycorpRegionNavigationService = region.NavigationService as CustomRegionNavigationService;
        if (moneycorpRegionNavigationService == null)
            throw new InvalidOperationException(
                "RequestNavigate that takes a container may only be used with a CustomRegionNavigationService");

        ((CustomRegionNavigationService)region.NavigationService).RequestNavigate(
            target, navigationCallback, containerToUse);
    }
}

I then modified the following PRISM  classes (they are too big to list here but I will show the most relevant parts,  if possible).

  • IRegionNavigationService (too much code to show, see the  demo code). This class is the main hook into the PRISM  navigation API. I simply modified it to have extra methods that would allow  a child container to be supplied, that would be used for the navigation /  dependency resolution
  • IRegionNavigationContentLoader this class is the class that  actually loads the item for the navigation (so this could be a view or a  viewmodel, so it was clear to me that I  needed to play with this guy  in order to get him to use a child container)

These custom implementations override the default PRISM  ones thanks to the following bootstrapper code:

C#
protected override void ConfigureContainer()
{
    base.ConfigureContainer();

    //custom region stuff to support child container navigation
    Container.RegisterType<IRegionNavigationContentLoader, CustomRegionNavigationContentLoader>(new ContainerControlledLifetimeManager());
    Container.RegisterType<IRegionNavigationService, CustomRegionNavigationService>(new ContainerControlledLifetimeManager());
}

This is the most relevant method of the modified

IRegionNavigationContentLoader 
class (though make sure you check out the  code for the rest)

C#
/// <summary>
/// Provides a new item for the region based on the supplied candidate target contract name.
/// </summary>
/// <param name="candidateTargetContract">The target contract to build.</param>
/// <returns>An instance of an item to put into the <see cref="IRegion"/>.</returns>
protected virtual object CreateNewRegionItem(string candidateTargetContract, IUnityContainer containerToUse)
{
    object newRegionItem;
    try
    {
        if (containerToUse == null)
        {
            newRegionItem = this.serviceLocator.GetInstance<object>(candidateTargetContract);
        }
        else
        {
            newRegionItem = containerToUse.Resolve<object>(candidateTargetContract);
        }
    }
    catch (ActivationException e)
    {
        throw new InvalidOperationException(
            string.Format(CultureInfo.CurrentCulture, "Can not create navigation target {0}", candidateTargetContract),
            e);
    }
    return newRegionItem;
}

 

With all this in place, we now have the following 2 things:

  1. You can go ViewModel first, which is what developers love and want to  use
  2. You can still use VisualState(s) which is what designers love and want  to use

Happy days, I was pleased that this worked out.

 

That's It

Although this is not a massive article, and it focuses on a rather niche area  of WPF / Silverlight development, I do think this sort of approach would be just  as valueable when developing a navigation system for Windows 8, that might have  to rely on you disposing of views, say when you leave a navigation frame of some  sort.

In fact my next series of articles will actually be on using 2 of the better  MVVM frameworks out there for Windows 8, so I will be able to put this idea  through its paces in a framework that is not strictly made up of composite views  (which PRISM  obviously supports)

After that I am going to have a break from UI stuff for a bit, and  concentrate on some Azure and Powershell, as these 2 things have been on my back  burner for quite a while now.

As always if you think this article was useful, or you liked it, any  votes/comments would be most welcome. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
GeneralMy vote of 5 Pin
Patricia Anderson13-Dec-17 2:21
Patricia Anderson13-Dec-17 2:21 
GeneralRe: My vote of 5 Pin
Sacha Barber13-Dec-17 5:20
Sacha Barber13-Dec-17 5:20 
QuestionHow do u load state into the viewmodel before sending it off for display? Pin
Crosscourt28-Jan-14 16:50
Crosscourt28-Jan-14 16:50 
AnswerRe: How do u load state into the viewmodel before sending it off for display? Pin
Sacha Barber29-Jan-14 0:05
Sacha Barber29-Jan-14 0:05 
GeneralMy vote of 5 Pin
Tariq Salah9-Sep-13 6:06
Tariq Salah9-Sep-13 6:06 
GeneralRe: My vote of 5 Pin
Sacha Barber10-Sep-13 23:11
Sacha Barber10-Sep-13 23:11 
Generali... Pin
db7uk29-Aug-13 9:03
db7uk29-Aug-13 9:03 
GeneralRe: i... Pin
Sacha Barber29-Aug-13 9:45
Sacha Barber29-Aug-13 9:45 
Yeah it's not going to win a Nobel prize or anything, but I feel
In the right place it's very useful
Sacha Barber
  • Microsoft Visual C# MVP 2008-2012
  • Codeproject MVP 2008-2012
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue

My Blog : sachabarber.net

Question5/5 Pin
Bennis12324-Aug-13 2:29
Bennis12324-Aug-13 2:29 
AnswerRe: 5/5 Pin
Sacha Barber24-Aug-13 3:59
Sacha Barber24-Aug-13 3:59 
GeneralMy vote of 5 Pin
Pete O'Hanlon22-Aug-13 5:12
subeditorPete O'Hanlon22-Aug-13 5:12 
GeneralRe: My vote of 5 Pin
Sacha Barber22-Aug-13 11:49
Sacha Barber22-Aug-13 11:49 
GeneralMy vote of 5 Pin
Sacha Barber20-Aug-13 20:48
Sacha Barber20-Aug-13 20:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.