For this lesson we'll start with the basics of a Prism application and cover how to achieve one of our requirements of creating a dynamic layout and sharing views between modules.
For length considerations, I won’t go into every detail of setting up a Prism solution. You can gather all this from the .chm file which comes with the download. Plus you can find the info on MSDN.
http://msdn.microsoft.com/en-us/library/dd458809.aspx
During this process we’ll go through creating templates that will contain regions for each module which get loaded dynamically.
With that, let’s get started. This application will be based off the Northwind database. I made slight modifications to it to demonstrate certain functionality. (The database isn't needed for this lesson.)
For our first lesson, we have our WPF application called NSTPrismSample. In this project we have the Bootstrapper class called from the App.xaml.cs code.
In the sample we create references from the main project to all our modules. You can do this dynamically or configure the modules and how they load in the app.config. The prism documentation will walk you through how to do this.
In our sample, our GetModuleCatalog() function loads our Order, Customer & Employee modules.
Code:
protected override IModuleCatalog GetModuleCatalog()
{
var _catalog = new ModuleCatalog().AddModule(typeof(OrderModule))
.AddModule(typeof(CustomerModule), "OrderModule")
.AddModule(typeof(EmployeeModule), InitializationMode.OnDemand, "OrderModule")
;
return _catalog;
}
In the Bootstrapper, we override the ConfigureContainer() method to make sure ShellView & ShellViewModel get loaded in our container.
Also in the Bootstrappe, CreateShell() as the name implies is were we initialize the Apps MainWindow and load our shell.
We resolve the ShellViewModel which contains a public method, SetTemplate which we use to set the template we want to display when the app first loads. You see we use the TemplateFactory singleton to get the customerTemplate. Then we call ShowView to display the template.
The concept I use to allow for dynamic regions is to create Templates. In the Templates directory, you’ll see CustomerTemplate.xaml and EmployeeTemplate.xaml user controls. These templates are designed for the Customer & Employee modules respectively.
You’ll see they contain unique Regions. Here is some sample xaml from the CustomerTemplate is loaded by default.
Code:
StackPanel x:Name="PnlCustomerRegion" Grid.Row="0" Grid.Column="1">
<ContentControl x:Name="CustomerRegion" cal:RegionManager.RegionName="{x:Static infrastructure:RegionNames.CustomerRegion}" />
</StackPanel>
<StackPanel x:Name="PnlOrderRegion" Grid.Row="1" Grid.Column="1">
<ContentControl x:Name="CustomerOrderRegion" cal:RegionManager.RegionName="{x:Static infrastructure:RegionNames.CustomerOrderRegion}" />
</StackPanel>
Next I created a singleton called TemplateFactory to make sure there is only ever one instance of each template.
In our ShellView, we create a ContentControl called TemplateUC as shown here:
[CODE
ContentControl x:Name="TemplateUC" Content="{Binding CurrentTemplate}"></ContentControl>
[/CODE]
The Content property is bound to a public UserControl property defined in the ShellViewModel named CurrentTemplate. Note is is customary in MVVM/Prism to set the a View’s datacontext to the ViewModel it uses. This usually takes place in the constructor of a ViewModel with code which looks like this.
Code:
this.View.ViewModel = this;
Code:
public ShellViewModel(ModuleManager moduleManager, IRegionManager regionManager, IEventAggregator eventAggregator, IShellView view) : base(view)
We get a reference to ModuleManager as we need to initialze the EmployeeModule when needed as it is set to load OnDemand when registered in the Bootstrapper.
Code:
.AddModule(typeof(EmployeeModule), InitializationMode.OnDemand, "OrderModule")
All of my ViewModels inherit from the ViewModelView<TView> class.
The other properties that you’ll find defined in the ShellViewModel are commands.
Code:
RelayCommand _showCustomerTemplateCommand; RelayCommand _showEmployeeTemplateCommand;
Remember there is a ContentControl bound to this property and is responsible for displaying our templates. With this way, your templates never close. Some like this so users can move around in the app without worrying about saving something to do so and you’re not constantly closing and reinitializing. If you want a module to be unloaded each time a new one is loaded, google for CompositeWPFApp. There is a good sample demonstrating how to do this. I also have a link to it in the forum section
http://www.compositedevpatterns.com/showthread.php?t=22.
What makes all this work. The CustomerTemplate is loaded which contains the CustomerRegion & the CustomerOrderRegion. Once it’s loaded, the code in the CustomerModule runs which Registers the needed objects for the CustomerModule and also binds it’s view(s) to the appropriate regions where they are to be displayed.
For now, focus on the following code that demonstrates how the CustomerModule’s CustomerView gets displayed.
Code:
CustomerViewModel _customerVM = _container.Resolve<CustomerViewModel>(); _regionManager.Regions[RegionNames.CustomerRegion].Add(_customerVM.View, "Customer View");
For now, here is a look at how the app will display when it first starts.
That brings this lesson to an end. Lesson 3 will focus on how to load views between modules.
Code for this sample is attached below. Please note for size considerations, all assemblies have been removed from the Bin directories. All assemblies needed for this application can be found in the SharedAssemblies folder. Please adjust your reference paths if need be. For the Telerik assemblies, if you have any issues, they are the trial versions of 2010 Q1.







Section Widget
Categories Widget (top-down)

