Composing a Prism UI using regions

Monolithic application are (or should be) a thing of the past. We want to create applications which are composable from various parts, preferably with a loose coupling to allow them to be added to or reconfigured with minimal effort.

There are various composable libraries for WPF, for this post I’m going to concentrate on Prism. Prism uses regions to allow us to partition your application by creating areas within a view for each UI element. These areas are known as regions.

Assuming we have a minimal Prism application as per my post Initial steps to setup a Prism application, then let’s begin by creating a “MainRegion” a region/view which takes up the whole of the Shell window.

  • In the Shell.xaml, add the name space
    xmlns:cal="http://www.codeplex.com/prism"
    
  • Replace any content you have in the shell with the following
    <ItemsControl cal:RegionManager.RegionName="MainRegion" />
    

    here we’ve created an ItemsControl and given it a region name of “MainRegion”. An ItemsControl allows us to display multiple items, equally we could have used a ContentControl for a single item.

  • We’re going to create a new class library for our view(s), so add a class library project to your solution, mine’s named Module1
  • To keep our views together create a View folder within the project
  • Add a WPF UserControl (mine’s named MyView) to the View folder, mine has a TextBlock within it, thus
    <TextBlock Text="My View" />   
    

    just to give us something to see when the view is loaded.

  • Add a class. I’ve named it Module1Module and add the following code
    public class Module1Module : IModule
    {
       private readonly IRegionViewRegistry regionViewRegistry;
    
       public Module1Module(IRegionViewRegistry registry)
       {
          regionViewRegistry = registry;   
       }
    
       public void Initialize()
       {
          regionViewRegistry.RegisterViewWithRegion("MainRegion", 
                   typeof(Views.MyView));
       }
    }
    

    Here we’re setting up an IModule implementation which associates a view with a region name.

  • Reference the class library project in the shell project

Using Unity

  • Now with our Unity bootstrapper, we need to add the module to the module catalog, as per the following
    protected override void ConfigureModuleCatalog()
    {
       base.ConfigureModuleCatalog();
       ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
       moduleCatalog.AddModule(typeof(Module1.Module1Module));
    }
    

Using MEF

  • Now with our MEF bootstrapper, we need to add the module to the module catalog, as per the following
    protected override void ConfigureAggregateCatalog()
    {
       base.ConfigureAggregateCatalog();
       AggregateCatalog.Catalogs.Add(new AssemblyCatalog(GetType().Assembly));
       AggregateCatalog.Catalogs.Add(new AssemblyCatalog(
               typeof(Module1.Module1Module).Assembly));
    }
    
  • In our view, we need to mark the class with the ExportAttribute, thus
    [Export]
    public partial class MyView : UserControl
    {
       public MyView()
       {
          InitializeComponent();
       }
    }
    
  • Now we need to change the module code to the following
    [ModuleExport(typeof(Module1Module), 
       InitializationMode=InitializationMode.WhenAvailable)]
    public class Module1Module : IModule
    {
       private readonly IRegionViewRegistry regionViewRegistry;
    
       [ImportingConstructor]
       public Module1Module(IRegionViewRegistry registry)
       {
          regionViewRegistry = registry;
       }
    
       public void Initialize()
       {
          regionViewRegistry.RegisterViewWithRegion("MainRegion", 
               typeof(Views.MyView));
       }
    }
    

Obviously in this sample we created a single region and embedded a single view, but we can easily create multiple named regions to truly “compose” our application from multiple views.