Prism is a set of libraries that allow developers to compose applications from separate components into a composite application. Composite meaning that the application functionality is split up into different modules that do not necessarily know about each other and then brought together to create an application.
From the Prism documentation: “Composite applications provide many benefits, including the following:
- They allow modules to be individually developed, tested, and deployed by different individuals or sub-teams; they also allow them to be modified or extended with new functionality more easily, thereby allowing the application to be more easily extended and maintained. Note that even single-person projects experience benefits in creating more testable and maintainable applications using the composite approach.
- They provide a common shell composed of UI components contributed from various modules that interact in a loosely coupled way. This reduces the contention that arises from multiple developers adding new functionality to the UI, and it promotes a common appearance.
- They promote re-use and a clean separation of concerns between the application’s horizontal capabilities, such as logging and authentication, and the vertical capabilities, such as business functionality that is specific to your application.
- They help maintain a separation of roles by allowing different individuals or sub-teams to focus on a specific task or piece of functionality according to their focus or expertise. In particular, it provides a cleaner separation between the user interface and the business logic of the application—this means the UI designer can focus on creating a richer user experience. ”
The Prism documentation is actually very good with showing you how to accomplish individual tasks. Where the documentation falls short is when you want to bring the differing concepts together. For example, the documentation does lead you through creating an application and showing a view, what it does not show you is how to create a view that possibly contains multiple “child” views
The goals for this article are
- Build the Prism library
- Setup an application shell that shows the main window
- Create a module that shows a view in the main window
- Create a module that shows a view in the first module
- Create a module that shows a second view in the first module
- Load the modules from a configuration file
But before we get to that we have to know;
How to get and setup Prism
Head on over to the Prism web site, http://www.codeplex.com/Prism, and download the Prism package. The site also serves as the community portal to ask questions of the Prism development team. Unzip the archive to the folder of your choice then open that folder up in explorer to view the files. The folder will contain several batch files that will conveniently open up several different sections of the Prism project. The two batch files that we are interested in at this time are named “Desktop & Silverlight – Open Composite Application Library” and “Desktop only – Open Composite Application Library”. The first batch file will open up a solution that will compile the libraries to use in WPF and Silverlight. If you are not doing any Silverlight application that you can use the second batch file. But you cannot use the libraries interchangeably (I think, I have not verified this as I do not do Silverlight development but otherwise there would be no need for separate projects). So, double click the batch file of your choice and the Prism solution will load up into Visual Studio 2008 (as of this writing). Then build the solution. The output libraries will be placed in <Prism root>CAL->Desktop
Creating the shell
I am going to assume that you know how to create an application solution, reference libraries and create class libraries in Visual Studio so I am not going to explain those details in depth. If you do not, you should study those items first. The first thing to do is to fire up Visual Studio 2008. Then create a new WPF application and name it whatever you want. For the purpose of this article I will name my solution “PrismArticle”. This is going to be the “shell” for our application. The shell is just a container to display the primary user interface. The shell can contain one of more views that are displayed to the user. Note that some of the code presented is more or less boilerplate code and copied from the Prism documentation.
- In the solution explorer, rename Window1.xaml to Shell.xaml.
- Then open the code behind file and rename the class name from Window1 to Shell
- Open Shell.xaml and change the Title attribute to “PrismArticle” or whatever you want.
- Add the CompositeWPF namespace to the Shell.xaml file, xmlns:cal=”http://www.codeplex.com/CompositeWPF”
- Remove the Grid tags from the XAML and add a ContentControl named “MainRegion” and set the region name to “MainRegion” for Prism:
- <ContentControl Name=”MainRegion” cal:RegionManager.RegionName=”MainRegion”/>.
- Add a new class to your project named Bootstrapper.cs.
- Add references to the Prism libraries:
- Add these using statements to the top of the Bootstrapper file.
- using Microsoft.Practices.Composite.Modularity;
- using Microsoft.Practices.Composite.UnityExtensions;
- using System.Windows;
- Change the Bootstrapper class to inherit from the UnityBootstrapper class.
class Bootstrapper : UnityBootstrapper
- Override the CreateShell method in the Bootstrapper class.
protected override DependencyObject CreateShell()
Shell shell = new Shell();
- Override the GetModuleCatalog method.
protected override IModuleCatalog GetModuleCatalog()
ModuleCatalog catalog = new ConfigurationModuleCatalog();
- Open the App.xaml.cs and override the Startup event.
protected override void OnStartup(StartupEventArgs e)
Bootstrapper bootstrapper = new Bootstrapper();
- Open the App.xaml file and remove the StartupUri since we are manually starting up the window in the bootstrapper.
Your final solution should look something like this. If all went well you should be able to build and run the application. But…
What the heck did we just do?
Everything up to step 8 should be pretty much self explanatory except for step 5.
Step 5 is where we setup a ContentControl in the shell window and named it “MainRegion”. Prism uses a concept called a Region that defines an area where a view is going to be displayed. If we had a module that mapped itself to the MainRegion, then that view would appear in that region. We will be doing just that in the next section.
Step 9 is where the application main window is created and shown.
Step 10 is where a catalog of the modules that the application uses is created. There are several different ways to accomplish this but for our example we are going to use a ConfigurationModuleCatalog which reads a configuration file and loads the modules defined in that file.
Step 11 is where the application starts up and instantiates the Bootstrapper.
Creating the first module
Before we create our first module we need to do a bit of configuration. Remember that we wanted to load our modules at runtime. To do that we have to have a place for the modules to be. So, in the solution folder create a “bin” folder, and then inside that folder create a “modules” folder. The bin folder is where we will put the executable and the modules folder is where the modules are going to go. Open up the project properties and on the Build tab set the output path to the bin folder that we just created.
Now for our first module. One thing that I deviate from the Prism documentation is that the Prism docs describe creating the regions to show the views in the shell. What I am going to do is to create a module that is shown in the main window and defines the regions for the application. This way the shell application remains static and the modules define the application. So our first module is the view that is going to be shown in the MainRegion that we defined before.
Add a Class Library project to the solution. For the sake of this example, I named my module project “MainWindowModule”. Open the Project properties select the Build tab and then change the output path to the modules folder under the bin folder that we created earlier.
Rename the Class1.cs file to MainWindow.cs. This will also rename the class to MainWindow. Add a reference to the Microsoft.Practices.Composite.dll. Then add a using statement to the top of the file:
Add a private variable to the class named _regionManager of type IRegionManager. The RegionManager allows us to access the regions defined in the application. Add a constructor to the class that accepts an IRegionManager parameter. Inside the constructor, make the _regionManager equal to the IRegionManager passed in.
Edit the class definition so that the class inherits from IModule. IModule is the interface that Prism uses to discover and initialize the modules. The method that we need to implement is the Initialize method. Inside the Initialize method, add the MainWindowView to the MainRegion through the region manager:
Now we need a MainWindowView to show in the MainRegion. Just to make things a bit tidy, add a new folder to our solution named “Views”. Inside the Views folder, add a new WPF user control named MainWindowView. To make everyone happy, you have to add another using statement to include the Views now.
Now, after all that what do you think will happen when you build and run the application now? Well, try it and see what happens. Go ahead. I will wait. Ready? What you should have seen is the same window we saw before we created the module and jumped through all those other hoops. If you set a break point in the Initialize method of the module you will find out that the method in not called. So what is up with that? Well before we can see the view in the main window we have to…
Configure the module
To configure the application to load our modules we have to add a configuration file to the executable project. So add a New Item -> Application Configuration File. I named my file App.config. This is the configuration file that the application is going to read to create the ConfigurationModuleCatalog in the Bootstrapper class. Add the following code to the app config file:
type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite" />
The Modules section defines what module to load and where to load it from. The “assemblyFile” attribute defines from where to load the module from. In this case we are loading the module from the Modules folder. The “moduleType” attribute is the name of the class that we want to load. The Prism docs call this a “type” which might be misleading for a beginner. This is the namespace and name of the class that implements the IModule interface. The last attribute simply defines the module name. There are other attributes that I will leave for another time. This is sufficient to get us going.
Now if you run the application you show at least get a stop at the break point you set earlier. But, chances are that you will see a blank window. Unless you open up the MainWindowView XAML file and put something in the window you won’t see anything. Go ahead and experiment and when you are finished playing around we will go on to the next phase.
Now that we know how to create and load a module the next thing that we want to do is to create a couple of child windows that we will display in the MainWindowView. We are not going to do anything fancy. Adding child views to the MainWindow is relatively painless. It’s basically the same as what we did for the MainWindowModule expect that the regions that we are going to define are in the MainWindowView. So, open up the MainWindowView XAML file and delete any content that you might have put there to experiment with. If you did do any experimenting you might have noticed that the contents of the MainWindowView were confined to a specific size when you resized the window. This is because of the Width and Height attributes in the view being set to 300. Go ahead and delete those two settings so that the view will fill the parent window.
Now add a Grid layout control and define two columns. Add a content control to column zero and add another content control to column 1. Being so imaginative I named the region in column 0 “LeftChild” and the region in column 1 “RightChild”. Of course you are free to improve on that design J
Add 2 more class libraries to the solution; name one “ChildOneModule” and the other “ChildTwoModule”. The setup for these modules pretty much mimics the steps we followed to create the MainWindowView. The code for both is about the same except for the region names.
Here is what I did. Feel free to experiment. The ChildOneView I simply changed the background color and added a label to identify the view. I did the same to the ChildTwoView except I made the color different.
Remember to change the output path for the two modules
Remember to add the Prism libraries to the module projects.
Remember to add the module definitions to the app.config file. Note that the order in which the modules are listed matters! If you list the child modules after the MainWindowModule , Prism will throw an exception saying that the RegionManager does not contain the <name of region> region. After running around in circles for about 2 hours, you will discover that the modules appear to be loaded from the bottom up. So the MainWindowView has to get initialized first so the other views have a region to get loaded into.
The final application will look like this when it’s all said and done.
Final result from all this
There we have downloaded and complied the Prism Library. Created a project that created a shell window using Prism, added a module to serve as the main window view and then finally added two more modules that served as two child views and loaded into the application dynamically loaded at runtime. This allows the UI views for the application to be developed separately from each other and to be totally independent code. Hopefully this is just the beginning of an exploration of the Prism framework. Depending on my work load and motivation I may continue writing about this. Next I think that I will explore getting our two child views to communication with each without them having to know anything about each other.
Here are links to the code for this article. Rename the archive from .doc to .zip before opening, this is a wordpress requirement. The code is presented as is with no warranty implied or guaranteed.
prism-article-part-1 This is the code for the initial project
prism-article-part-2 This is the code for the second part of the article
prism-article-part-3 This is the final code solution