Click here to Skip to main content
Click here to Skip to main content

PRISM application from the beginning: Part II

By , 13 Dec 2012
Rate this:
Please Sign up or sign in to vote.

PRISM application from the beginning

The  article series collection

Introduction

Last article we created an initial solution to start working on it to develop a PRISM application. In this article we're going to use the solution we finished in part I. We had a Shell and now it's time to define regions and create modules to give some funcionality.

Regions

A Region is a "Placeholder" for dynamic content  that is going to be presented in your UI or in your Shell. It's analogous  to the concept of the content placeholder in the ASP.NET MasterPage. It's simply a named location that you can use to define where the view will appear.

In this Project, we're going to create two regions:

  • Toolbar Region
  • Content Region
The main idea is to build a Module with two views. One view for each Region:

More specifications of the Region component:

  • Regions can be defined in the Shell or in another View.
  • Regions has no knowledge of views: you can locate and add content to a Region without exact knowledge of how and where that Region is defined. This allows the appearance and layout to change affecting only the module or View.
  • Region can be created in code or in XAML
  • A Region implements IRegion interface (important when adding programatically access to the Region).

The Region Manager  

Is the responsible for managing Regions in your application:

  • Maintains the collection of Regions
  • Provides a RegionName attached property,
  • Maps RegionAdapter to controls  (RegionAdapter is basically responsible for associating a Region with the host it controls). RegionAdapter that PRISM provides to you are:
    • ContentControlRegionAdapter: adapts controls of type content control.
    • ItemsControlRegionAdapter:  adapts controls of type items control.
    • SelectorRegionAdapter:  adapts controls of type selector (like tabs).
  • Provides a RegionContext attached property, is like a dataContext. It's the technique to share the data between the parent View and the Child View.

Add Regions to project  

We want to create the Regions to define  the layout of the Shell. So open the project PrismApplication and open the Shell.xaml. We are going to create a DockPanle to have in the Top, the Toolbar and the content Region in the remaining space:

<Window x:Class="PrismApplication.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Shell"> 
    <DockPanel LastChildFill="True">
        <ContentControl DockPanel.Dock="Top"> </ContentControl>
        <ContentControl /> 
    </DockPanel> 
</Window> 

If you notice, the DockPanel we created with the attribute LastChildFill=True, this means that the last defined item in the DockPanel, will fill the remaining space.

Now we have to identify these ContentControls as Region. First of all, we need to add a namespace for using PRISM and the RegionManager:

xmlns:prism="http://www.codeplex.com/prism" 

For identify a Controls asa Region, we have to set the RegionName property of the RegionManager. This can be done by adding the attribute to the ContentControl:

prism:RegionManager.RegionName="REGION_NAME" 

You can just specify a REGION_NAME by using a string, but it's better to use a constant. For this we're going to create a new class called RegionNames in the PrismApplication.Infrastructure project. This is the class:

namespace PrismApplication.Infrastructure
{
    public class RegionNames
    {
        public static String ToolbarRegion = "ToolbarRegion";
        public static String ContentRegion = "ContentRegion";
    }
}   

Now come back to the Shell.xaml file where we were specifying the Regions and add another namespace to access to this constants:

xmlns:inf="clr-namespace:PrismApplication.Infrastructure;assembly=PrismApplication.Infrastructure" 

Like we're using another project from the solution, we have to add a Reference to the PrismApplication.Infrastructure project:

and set the names of the Regions in the Shell.xaml adding the attribute  REGION_NAME like this:

prism:RegionManager.RegionName="{x:Static inf:RegionNames.ToolbarRegion}"  

x:Static references any static property, field, constant or enumeration value defined in procedural code.

And the final Shell.xaml is the following:

<Window x:Class="PrismApplication.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://www.codeplex.com/prism"
        xmlns:inf="clr-namespace:PrismApplication.Infrastructure;assembly=PrismApplication.Infrastructure"
        Title="Shell"> 
    <DockPanel LastChildFill="True">
        <ContentControl DockPanel.Dock="Top" prism:RegionManager.RegionName="{x:Static inf:RegionNames.ToolbarRegion}"> </ContentControl>
        <ContentControl prism:RegionManager.RegionName="{x:Static inf:RegionNames.ContentRegion}"/> 
    </DockPanel> 
</Window> 

The Regions have been specified and now it's time to deal with Modules because Modules contains Views than will be injected into Regions.

Modules

This is the time to decide how you want to modularize your application.  Modular apps are broken into modules.  Each module is going to load some services for others to consume, play a part in UI composition and have a chance to integrate itself with the rest of the application.

A Module is a class that implements the IModule interface. This is what identifies a module to the PRISM library and it has a single method in it called Initialize. This method is the responsible for initializing the model and integrating into your PRISM application.

Creating a Module 

To start creating a Module, select in the Solution Explorer the Folder Modules and right-click ->Add -> New Project...  and select WPF User Control Library and the path .\Src\Modules:

 

Once created, delete the file UserControl1.xaml, and add References to the PRISM libraries in .\Libs\Prismv4.1 to use the IModule interface.

Next step is to Add a new class to the Module, called ModuleAModule that is going to implements IModule interface, so we need the Modularity package:

using Microsoft.Practices.Prism.Modularity;   

and implement the method from the interface having the class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.Modularity;
namespace ModuleA
{
    public class ModuleAModule : IModule
    {
        public void Initialize()
        {
            throw new NotImplementedException();
        }
    }

At this time we have the module and next step will be register and discover the module with the Bootstrapper.

Module Lifetime 

The module lifetime can be reflected as the following :

 

Register And Discover Modules 

All the modules that needs to be loaded at runtime on your application are defined into what's called the ModuleCatalog. This catalog contains information about all the modules loaded. It knows:

  • location
  • order in which are going to be loaded
  • relations between modules, (if a module depends on another module)

Load Modules 

The assemblies that contain the modules are loaded into memory. This phase may require the module to be downloaded from the web or otherwise retrieved from some remote location or local directory.

We can control when to load it: as soon as possible, (when available) or when the application needs it (on-demand).

Initialize Modules 

When a Module is being initialized, an instance of the Module is being created and the method IModule.Initialize is executed.

The Initialize method will contain the code for:

  • Register types
  • Subscribe to services or events
  • Register shared services
  • Make compose views into the Shell

This method is where we're going to put all the code that does all the work to get your Module ready for consumption in your PRISM application.

Register a Module in our project 

First step here is to Add a Reference to the Module Project in the PrismApplication project. Once added,  we edit the Bootstrapper class and override the ConfigureModuleCatalog(), then add the following line to use ModuleCatalog Entity and ModuleAModule:

using Microsoft.Practices.Prism.Modularity;
using  ModuleA; 

Having this new piece of code:

protected override void ConfigureModuleCatalog()
{
    base.ConfigureModuleCatalog();
    ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
    moduleCatalog.AddModule(typeof(ModuleAModule));
}  

Now our Module is successfully registered by the Bootstrapper through code.

Next step is to create a View in the Module to inject it in a Region of the Shell.

 Views

Definition of a View 

A View in PRISM is not a interface that the user uses to interact with the application, in PRISM a View is a portion of the user interface, it's a smaller unit of the user interface, it's encapsulated a piece of functionality and decoupled from other parts of the user interface.

For example, in Microsoft Outlook we can see the Views its uses, each view has a functionality:

  • Toolbar
  • Preview
  • List of messages...

  • A View can be made of multiple Views (Composite Views, but we'll see this as an advanced subject).
  • A View can be created with UserControl, Page, DataTemplate,...
  • Can have multiple instances of a View

 Create a View in our project 

Go to project ModuleA an Add -> UserControl. Give to it the name of ToolbarA, then edit the file ToolbarA.xaml and insert a Button:

<UserControl x:Class="ModuleA.ToolbarA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Button>ToolbarA</Button>
    </Grid>
</UserControl> 

Add another UserControl with the name ContentView,  and edit the file ContentView.xaml and add a TextBlock:

<UserControl x:Class="ModuleA.ContentA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="Content A" FontSize="40"/>
    </Grid>
</UserControl> 

Register the View in the container 

Next step is to register the View in its container. In order to do that open the ModuleAModule.cs file and start implementing the Initialize method from IModule interface.

We need to add a new public constructor that receive an IUnityContainer parameter, so we need to add the line:

using Microsoft.Practices.Unity;  

Then we need a reference to the container to save the container in the constructor:

IUnityContainer _container;
public ModuleAModule(IUnityContainer container)
{
    _container = container; 
} 

And we can register the View in the Initialize method. The code of moduleAModule.cs is the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
namespace ModuleA
{
    public class ModuleAModule : IModule
    {
        IUnityContainer _container;
        public ModuleAModule(IUnityContainer container)
        {
            _container = container;
        }
 
        public void Initialize()
        {
            _container.RegisterType<ToolbarA>();
            _container.RegisterType<ContentA>();
        }
    }
} 

Now we've registered the Views but are not still visible because next step is to start composing our view.

MVVM (Model View View-Model) 

From: http://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx 

The Model-View-ViewModel (MVVM) pattern helps you to cleanly separate the business and presentation logic of your application from its user interface (UI). Maintaining a clean separation between application logic and UI helps to address numerous development and design issues and can make your application much easier to test, maintain, and evolve. It can also greatly improve code re-use opportunities and allows developers and UI designers to more easily collaborate when developing their respective parts of the application.

Using the MVVM pattern, the UI of the application and the underlying presentation and business logic is separated into three separate classes: the view, which encapsulates the UI and UI logic; the view model, which encapsulates presentation logic and state; and the model, which encapsulates the application's business logic and data.

 

The View 

Has the following key characteristics:

  • The view is a visual element, such as a window, page, user control, or data template. The view defines the controls contained in the view and their visual layout and styling.
  • The view references the view model through its DataContext property. The controls in the view are data bound to the properties and commands exposed by the view model.
  • The view may customize the data binding behavior between the view and the view model. For example, the view may use value converters to format the data to be displayed in the UI, or it may use validation rules to provide additional input data validation to the user.
  • The view defines and handles UI visual behavior, such as animations or transitions that may be triggered from a state change in the view model or via the user's interaction with the UI.
  • The view's code-behind may define UI logic to implement visual behavior that is difficult to express in XAML or that requires direct references to the specific UI controls defined in the view.

The  View-Model Class 

Has the following key characteristics:

  • The view model is a non-visual class and does not derive from any WPF or Silverlight base class. It encapsulates the presentation logic required to support a use case or user task in the application. The view model is testable independently of the view and the model.
  • The view model typically does not directly reference the view. It implements properties and commands to which the view can data bind. It notifies the view of any state changes via change notification events via the INotifyPropertyChanged and INotifyCollectionChanged interfaces.
  • The view model coordinates the view's interaction with the model. It may convert or manipulate data so that it can be easily consumed by the view and may implement additional properties that may not be present on the model. It may also implement data validation via the IDataErrorInfo or INotifyDataErrorInfo interfaces.
  • The view model may define logical states that the view can represent visually to the user.

The Model class 

The model has the following key characteristics:

  • Model classes are non-visual classes that encapsulate the application's data and business logic. They are responsible for managing the application's data and for ensuring its consistency and validity by encapsulating the required business rules and data validation logic.
  • The model classes do not directly reference the view or view model classes and have no dependency on how they are implemented.
  • The model classes typically provide property and collection change notification events through the INotifyPropertyChanged and INotifyCollectionChanged interfaces. This allows them to be easily data bound in the view. Model classes that represent collections of objects typically derive from the ObservableCollection<T> class.
  • The model classes typically provide data validation and error reporting through either the IDataErrorInfo or INotifyDataErrorInfo interfaces.
  • The model classes are typically used in conjunction with a service or repository that encapsulates data access and caching.

Adapting our code to MVVM design pattern

We're going to use the View-first approach of the MVVM patter. This means the view is what drives the creation or discovery of the view model.

IView, IViewModel  

First thing to do when create a MVVM application is to create into the Infrastructure project a new Interface called IView. (Add-> New Item... and select interface). and another Interface called IViewModel.

In the IView, create a field of type IViewModel and in the IViewModel a field  of type IView:

namespace PrismApplication.Infrastructure 
{
    public interface IViewModel
    {
 
    }
}  
namespace PrismApplication.Infrastructure
{
    public interface IView
    {
        IViewModel ViewModel { get; set; }
    }
} 

IContentAView, IContentAViewViewModel 

Then we need to add a interface in the ModuleA project. (Add-> New Item... and select interface) and call it  IContentAViewViewModel implementing IViewModel with the line using PrismApplication.Infrastructure;. The  IContentAViewViewModel.cs looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PrismApplication.Infrastructure;
namespace ModuleA
{
    public interface IContentAViewViewModel : IViewModel
    {
    }
}

Now into the ContentA.xaml.cs we have to add the implementation of IView:

public partial class ContentA : UserControl, IView
{
    public ContentA(IContentAViewViewModel viewModel)
    {
        InitializeComponent();

        ViewModel = viewModel;
    }

    public IViewModel ViewModel
    {
        get
        {
            return (IViewModel)DataContext;
        }
        set
        {
            DataContext = value;
        }
    }
} 

The get method just return the DataContext casted as a IViewModel.

So when we create an instance of this view (ContentA), this view is goint to create an instance of IContentAViewViewModel and when this is created, we assign the ViewModel property to the viewmodel instance which is setting our DataContext. This is the binding between the ViewModel and the View

ContentAViewViewModel 

Let's create the ViewViewModel. In the ModuleA project create a new class called ContentAViewViewModel that will implement the IContentViewViewModel interface.

Here we're going to create a simple constructor:

public class ContentAViewViewModel : IContentAViewViewModel
{
    public ContentAViewViewModel()
    {
    }
}

Register types 

In the final step we have to register all of the new types in the container. Go to the class ModuleAModule and add the Interface IContentAViewViewModel when registering type ContentAViewViewModel in the initialize method:

public void Initialize()
        {
            _container.RegisterType<ToolbarA>();
            _container.RegisterType<ContentA>();
            _container.RegisterType<IContentAViewViewModel, ContentAViewViewModel>();
        } 

This means that when container ask for an IContentAViewViewModel, it has to resolve it to an instance of ContentAViewViewModel.

 View Composition 

This part is where the view is constructed, all the visual elements are created and placed in the Regions of the Shell. You can create and display these elements by two ways:

  • Automatically: View Discovery
  • Programmatically: View Injection

We'll use the View Discovery method.

View Discovery 

Views are added automatically. To enable it, just need to set the relationship in the Region view registering between the region name and the type of view by using the RegionManager.RegisterViewWithregion(name,type)

Adding View Discovery to code 

Go to the class ModuleAModule and we'll make some changes,

First, add the line:

using Microsoft.Practices.Prism.Regions; 
to start working with RegionManager. In the constructor, add a parameter of type IRegionManager, that will save it into a new private field:
IRegionManager _manager;
public ModuleAModule(IUnityContainer container, IRegionManager manager)
{
  _container = container;
  _manager = manager;
}  

And now we have to enable View discovery for the Toolbar Region, add first following line to reach the regionNames:

using PrismApplication.Infrastructure; 

and enable  discovery when initializing:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Prism.Regions;
using PrismApplication.Infrastructure;
 
namespace ModuleA
{
    public class ModuleAModule : IModule
    {
 
        IUnityContainer _container;
 
        IRegionManager _manager;
 
        public ModuleAModule(IUnityContainer container, IRegionManager manager)
        {
            _container = container;
            _manager = manager;
        }

        public void Initialize()
        {
            _container.RegisterType<ToolbarA>();
            _container.RegisterType<ContentA>();
            _container.RegisterType<IContentAViewViewModel, ContentAViewViewModel>();
 
            _manager.RegisterViewWithRegion(RegionNames.ToolbarRegion, typeof(ToolbarA));
            _manager.RegisterViewWithRegion(RegionNames.ContentRegion, typeof(ContentA));
        }
    }
}

Now when the Region is created will automatically initialize and instantiate the ToolbarA and the ContentA.

Next articles

In the next articles, we're going to use a project with much more sense, a real-life project with the same components that we have.

With that project we'll see a lot of new things: 

  •  MVVM: Interaction between View, ViewModel, and model classes 
  • Navigation
  • Communication between modules 
  • WPF (constructing a high-level view) 

As you can see, the aim of this series of articles is to start from PRISM architecture, using MVVM and using all the possibilities that PRISM offers. 

Footnotes

The code is the same example that Introduction to PRISM  course in Pluralsight site.  This is an example to learn the basics of PRISM but henceforth we're going to use another example of the real-life, such an address book or a orders catalog from a company. The code will be available in the next chapter to work with it.

In this chapter we've seen the MVVM patter. To be more familiar with it I recommend to read it and understand it more closely in other pages or manuals and start with the next chapter when MVVM pattern is clearly in your mind.

License

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

About the Author

juanlubarreda
Technical Lead
Spain Spain
I'm a Software Engineer from Spain, working in an R&D company.
 
Very interested in .NET technologies, always inmersed in a no-end learning process.

Comments and Discussions

 
QuestionPRISM application from the beginning: Part II PinmemberLu1zZz25-Mar-14 14:54 
GeneralMy vote of 5 Pinmembertaleofsixstrings3-Mar-14 3:33 
QuestionIContentAViewViewModel created? Pinmembertaleofsixstrings3-Mar-14 3:32 
SuggestionExcellent article,please present part III ASAP. Pinmemberrslucn2-Mar-14 0:57 
QuestionPrism Article PinmemberMember 1054947525-Jan-14 13:51 
QuestionThird Part Pinmembergoti_5127-Dec-13 8:06 
QuestionMy Module could not load until I added [ModuleExportAttribute] PinmemberVitaliy Markitanov31-Oct-13 5:50 
QuestionPart III PinprofessionalIxcoatl22-Oct-13 5:18 
GeneralCan't wait for the rest of your article on this subject. Thanks again! PinmemberMember 12495467-Oct-13 8:50 
GeneralGreat Step by Step PinmemberjluqueCodeProject21-Aug-13 21:09 
QuestionCool PinmemberSilvabolt20-Jun-13 6:14 
QuestionRE: PRISM application from the beginning: Next article PinmemberDush Abe20-May-13 19:04 
AnswerRe: RE: PRISM application from the beginning: Next article Pinmemberjuanlubarreda20-May-13 20:29 
GeneralRe: RE: PRISM application from the beginning: Next article Pinmembersedan121-May-13 23:11 
GeneralRe: RE: PRISM application from the beginning: Next article PinmemberOscar Mathew29-Jul-13 0:53 
GeneralRe: RE: PRISM application from the beginning: Next article Pinmemberjuanlubarreda31-Jul-13 21:06 
GeneralRe: RE: PRISM application from the beginning: Next article Pinmembermathiasbanda22-Jan-14 1:22 
QuestionMy Vote of 5 PinmemberMember 78648236-May-13 3:13 
GeneralMy vote of 5 Pinmemberstibee3-May-13 23:47 
GeneralMy vote of 5 PinmemberSteveQ561-May-13 8:58 
GeneralAwesome Articles! Pinmemberjpm000410-Mar-13 21:24 
QuestionMy vote is 5 Pinmembersouthsouth3-Mar-13 9:33 
QuestionJust waiting the third part PinmemberAngel161622-Jan-13 21:16 
My favourite serie of articles about MVVM. I'm just waiting the third part.
GeneralMy vote of 5 PinmemberAngel161622-Jan-13 21:15 
QuestionRegarding menu bar PinmemberTridip Bhattacharjee13-Dec-12 20:04 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 13 Dec 2012
Article Copyright 2012 by juanlubarreda
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid