Anda di halaman 1dari 16

Starting with Prism - Part 1 of n

Introduction
Prism provides the guidance to create composite applications and help us to design loosely coupled components, which can be
integrated and developed in seamless manner. Like every other application, Prism application also need to get start from
somewhere. And when coming to Prism, it is Bootstrapper and Shell. These two things help any Prism application up and
running. In this article, we will look more into Bootstrapper and its process. So, gear up and let's get started...

Bootstrapper
So, what is Bootstrapper? Bootstrapper is the class, which is responsible for initializing our application. Now question is what to
initialize? So, the first thing is to initialize is the Core Services and then the Application Specific Services.
Core Services: These are non-application specific services that Prism library provide to us. These services include:

IModuleManager - Responsible for retrieving application's modules


IModuleCatalog - It is used to register the modules
IModuleInitializer - Responsible for initializing the modules
IRegionManager - These are visualcontainers for our UI
IEventAggregator - It allows us to create events
ILoggerFacade - This is wrapper for logging mechanism
IServiceLocator - This is used to give application access to your container
Application Specific Services: Apart from core services, Prism also initializes some application-specific services. These are the
services, which are specific to our application and which is common among all application modules. For example, if you are
working on RSS type application, in that case, RSS Feed service will be application-specific service, which will be used by almost
all the modules to read the feeds.

Bootstrapper Process
Bootstrapper is the very important class, which gives us control of every component, application gets wired up. Prism library
provides a default abstract Bootstrapper base class, that has number of virtual methods. Let's go ahead and take a look a
Bootstrapper process. Keep in mind that most of the stages of this process will be covered in more detail in subsequent articles.

First thing is to create a LoggerFacade, which will mainly deal with logging
Next one has to configure Module Catalog
Then one has to create a container and one can use any container of their choice such as Ninject, Unity, MEF, etc. Prism
library actually includes, two Bootstrapper classes. One called the UnityBootstrapper and another one is MEF, which
includes most of thefunctionality necessary to use Unity or MEF as your dependency injection container
Next one has to configure default Region Adapter Mappings. So, we have to create a custom Region Adapter, which we
will register there
Next we would configure our default Region Behaviors
Then we will register our framework Exception Types
Next we would create the Shell
Then Shell will be initialized
And lastly Modules will be initialized
Please keep in mind that we need not to implement each and every single stage.

Sample code for UnityBootStrapper


In order to use Unity, one needs to add below references to the project:
Microsoft.Practices.Prism.dll
Microsoft.Practices.Prism.UnityExtensions.dll
Microsoft.Practices.Prism.Unity.dll
Next we needs to add a class named Bootstrapper, as:
public class Bootstrapper : UnityBootstrapper
{
protected override System.Windows.DependencyObject CreateShell()
{
return Container.Resolve<Shell>();
}
protected override void InitializeShell()
{
2

base.InitializeShell();
App.Current.MainWindow = (Window)Shell;
App.Current.MainWindow.Show();
}
}
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}

Regions
Here I am going to talk about the role of Regions in any Prism application. Here we will discuss, what Regions are and what role
they play in our application. We will also look into RegionManager and how it manages our Prism application. We will also touch
upon RegionAdapter and the relationship between Region and RegionManager.Then we will see, how to create a custom region
as it is necessary for the controls, which Prism doesn't support.

What are Regions?


A Region is simply a placeholder for any dynamic content, which is going to be presented in our UI. Regions are similar to the
ASP.NET's content placeholders. It is simply a named location, that one can use to define, where our View will appear. I hope,
you remember, we talked about the concept of the Shell earlierand how the Shell can contain Regions, where we will inject our
Views into.
Now let's take an example quickly. In this example, we will have MenuBar Region and a Content Region.

These regions define areas of the UI, where our View is going to be injected. Each Region should be explicitly named and
describe the type of content in which we are going to inject the Region. So, given a Module with a two views named MenuBar
View and Content View. These views will be injected to their respective regions. It means, each Region will have it's
corresponding View. Here MenuBar View will be injected to MenuBar Region and Content View will be injected to Content
Region.
Now, keep in mind, that we just don't have to be in the Shell as Region can also be defined in another View.

Regions have no knowledge of Views. We can locate content to a Region, without exact knowledge of how and where the
Region is defined. This allows the layout change without effecting the Views in the Module. Eg; In above figure, we can shift
'MenuBar Region' to left of 'Content Region', but our 'MenuBar view' will be injected to 'MenuBar Region' and 'Content View',
will be still placed into 'Content Region'. So, in this way, we are able to re-designour Shell, without having to re-code any type
of infrastructure code.
Regions can be created in code or in XAML. One thing, which we need to keep in mind id, Region is not a control, but is a host
control and it always implements a IRegion interface. This is important to know as it will be used, when you
willprogrammaticaccess your Region.

Region Manager
I hope, as many of you have probably guessed that a Region Manager is responsible for managing the Regions in the
application. It does this, by maintaining the collection of regions. It also provides a RegionName property. This is actually an
attached property, that is used to create Regions by applying it, to the host control and this can be again done through XAML or
through code.
Region Manager also maps RegionAdapter to controls. Now, RegionAdapter is responsible for associating a Region with the host
control. In order to expose, UI control as a Region, it must have a RegionAdapterand each RegionAdapter adapts a specific type
of UI control.
Prism provide us with four RegionAdapter:

ContentControlRegionAdapter - which adapts controls of type content control


ItemsControlRegionAdapter - which adapts controls of type content control
SelectorRegionAdapter - which adapts controls provided by Selector class, such as tab control
TabContorlRegionAdapter - this is contained only by SL version because in SL, it is not a part of Selector class
and behaves bit differently from WPF control
Now, if Prism provided RegionAdapter, doesn't meet our need, we can definitely create our own.
Region Manager also provides a RegionContext attached property. This property is similar to the concept of DataContext. It
is a technique to share a data between a parent view and a child view. RegionContext can also be set form the code or from
XAML.

Sample code snippet to create a Region


In order to create a Region, one needs to add below references to the XAML (Shell):
xmlns:local="http"//www.codeplex.com/prism"
Next we needs to create Regions as , as:
<DockPanel>
<ContentControl DockPanel.Dock="Top" local:RegionManager.RegionName="MenuBarRegion"/>
<ContentControl local:RegionManager.RegionName="ContentRegion"/>
</DockPanel>
Now, go to the Module class and add the following:
4

public class MyModule : IModule


{
IUnityContainer _container;
IRegionManager _regionManager;
public MyModule(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = _regionManager
}
public void Initialize()
{
regionManager.RegisterViewWithRegion("MenuBarRegion", typeof(MenuBarView));
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ContentView));
}
}

Custom Region
There are times, when we need to use third party control or a custom controlas a Region host. There is no issue, as far as our
custom control can use the Prism provided RegionAdapters. But it can not be the case always. So, we need to create our own
RegionAdapter to adapt a custom control as a Region host. There are only a few steps, we need to follow:
Derive your class from RegionAdapterBase<T>
Implement CreateRegion method - this method returns one of the following objects
1. SingleActiveRegion (mainly used for content control)
2. AllActiveRegion (mainly used for items control)
3. Region(mainly used for controls derived from the Selector class)
Implement Adapt Method - this is to actually adapt your control
Register your adapter

Modules
In this article, we will talk about how to take other views/logic and broken down into a small pieces called Modules and use
them in your Prism application. We gonna start-up by talking about What a Module is, then registering Modules, loading
Modules and then we will talk about how to initialize a Module.

What is a Module?
You can think Module as a building block for our Prism application. It is a package that contains all the functionalities and
resources required for our application. Prism provides a support for run-time Module management in our application, in which
each Module can be developed and tested independently. Prism application loads the Modules as and when they are required.
Before moving forward, lets have a look at how our application was architected inside Visual Studio prior to the concept of
Modules.

In above figure, we have single solution and inside that we have single project and within that project we have every single view,
all our services, and all our business logic. I mean, single project contain each and everything, which is required for my project.
Now, we want to identify, how we can break down our application into smaller pieces called Modules as shown in below figure:

Now, if you look at our solution, you will see that we still have that main project with Shell and Regions in it whereas all the
major functionality is defined outside the main project. From above figure, we can see that each Module is independent of each
other. Here each module can be single class library or a DLL or a XAP, that includes a collection of other related components.
Each Module has a central class that implements the IModule interface and this is what identifies as a library to a Prism library.
This interface has a single method in it called Initialize, which is responsible for initializing a Module and integrating it to your
Prism application and all can talk later on with this module.
Creating a Module
6

In order to create a Module, one needs to add below reference to the project:
Microsoft.Practices.Prism.dll
Next we need to add a class library and inherit IModule interface, as:
public class MyModule : IModule
{
public void Initialize()
{ // TO DO: }
}

Registeringand Discovering Modules


Allthe Modules need to be loaded at runtime in particular application.ModuleCatalog contains information about all Modules
to be loaded, it knows thelocation and it knows the order in which they are going to be loaded. It evenknows that a particular
module is dependent on another Module. I hope, onething is clear that we need to register our Module to ModuleCatalog via
code,XAML or by a configuration file.

Loading Module
Well, next process in Module lifetime isloading a Module. All of the assemblies that contain the Module need to beloaded into
the memory. This can be from disk, directory or the web link (only forSL). Prism allows us to control, when to load a module.
They can be loaded assoon as possible, which is known as When available or can be loaded, when aapplication need them,
which is known as On-demand.

Guidelines for loading the Module


It is always good to decide prior thatwhen we want to load our Module. Never forget to think on below points:
Is it required to run the application If it is, then it must be downloaded with the application and has to beinitialized
when the application loads
Always used If it is, it can bedownloaded in the background, when it becomes available
Rarely used If this is the case, thenit can be downloaded in the background and can be initialized on demand

Initializing Module
The last phase in the Moduleslifecycle is initializing Modules. IModule.Initialize() does this for us. In this method, we
write a code to register our types, we can even subscribe toservices or events. We can even work with shared services. We can
also compose our viewinto the Shell. So, basically the Initialize() method is where you can put allyour code which make
your Module ready for consumption in our Prism application.

Views
Most of the applications require some type of interface with user can interact with. Here we will talk about Views, which will
provide the interface to the user and will also see, how to add views to the Prism application. We will touch upon, what a View is,
about View Composition, View Discovery and View Injection.

What is a View?
In layman term, View is simply the interface that user uses to interact with the application. But in Prism application, this concept
is bit different. In Prism, View is only the portion of user interface. It is a smaller unit of user interface, which encapsulates a piece
of functionality and is coupled with other parts of user interface. Lets take an example of Outlook. In Outlook, we have toolbar
at top and a navigation bar on left side. If you will look closely into it, you will find that, both of these parts have no dependency.
For example, outlook toolbar can probably have its own View and has no dependency on other parts of the application. Its main
function is to send messages and the actions which are needed to be performed. And the same is true for navigation area, the
email list, the content area and even for a status bar. So, we can see that a Outlook is composed of multiple Views.
7

Composite View
In Prism, a View can be made up of multiple Views, which is also called as Composite View. Here Composite View can be think of
Parent with, having its child view, again sub child view, etc. View can be composed of User control, Page, Data Template, etc.
Basically, it can be anything, which can be used to display information to the user. We can also have multiple instances of Views.
For example, tab control with a number of tabs showing the same view.
Please keep in mind, while creating a View, design patterns are not required. There is nothing specific to the Prism library that
requires you to use the design pattern to bind a View. But one can use any of the available design patterns for creating a View.
Sample code for implementing Views
Lets create a View, by adding a user control MenuBarView:
<UserControl>
<Button>MenuBar</Button>
<UserControl>
Please note, here I am not using any type of design pattern namely MVC, MVP to create my views. Next thing, we need to do is
to register our View with container. In order to do that, you need to open your Module class. In the Initialize() method,
we need to register our view with our container. And of course, in order to do this we need a reference to a container.
Likely, it is pretty easy again. Lets start by adding reference of Microsoft.Practices.Unity.dll. Then we need to add a constructor
for our Module class as:
public class MyModule : IModule
{
IUnityContainer _container;
public MyModule(IUnityContainer container)
{ _container = container ;}
public void Initialize()
{ _container.RegisterType<MenuBarView>(); }
}
So, whats happening in above code. Here, whenever Module is created, Prism is identifying a container, which is Unity container
here. Once the container is identified, our Initialize() method is called and we start registering our types with the
container So, once our types are registered with container, we can start using them in the module.
Composing Views
So, next step is composing our views. Here, I am going to use MVVM. Most of us are already aware, that in MVVM, we start with
creating interfaces. Here also, I am creating public interfaces named IView and IViewModel. Now,
Lets create a View, by adding a user control MenuBarView:
public interface IView
{
IViewModel ViewModel {get; set;}
}
and
public interface IViewModel
{
IView View {get; set;}
}
Please remember, in MVVM, ViewModel can never have direct reference of View and thats the reason, I created IView. Now
add another interfaces for our View and ViewModel named IMenuBarView and IMenuBarViewModel, as:
public interface IMenuBarView: IView { }
Now, go to the View (MenuBarView) code behind implement the interface IMenuBarView, as:
public partial class MenuBarView: UserControl, IMenuBarView
8

{
public MenuBarView()
{
InitializeComponent();
}
public IViewModel ViewModel
{
get{ return (IMenuBarViewModel)DataContext;}
set{ DataContext = value; }
}
}
Next thing, we need to do is, go to IMenuBarViewModel and implement IViewModel as:
public interface IMenuBarViewModel: IViewModel
{
public MenuBarView()
{
InitializeComponent();
}
public IViewModel ViewModel
{
get{ return (IMenuBarViewModel)DataContext;}
set{ DataContext = value; }
}
}
Now, we will create a ViewModel named MenuBarViewModel,as:
public class MenuBarViewModel: IMenuBarViewModel
{
public MenuBarViewModel( IMenuBarView view)
{
View = view;
View.ViewModel = this;
}
public IView View
{get; set;}
}
We are not yet done. First, we need to register all our new types to container, inside Module class, as:
public class MyModule : IModule
{
IUnityContainer _container;
public MyModule(IUnityContainer container)
{
_container = container ;
}
public void Initialize()
{
_container.RegisterType<IMenuBarView, MenuBarView>();
}
}
What above snippet is doing is, whenever Ill ask for type IMenuBarView, Ill get instance of MenuBarView and we also
have to do the same thing for our IMenuBarViewModel, as:
public class MyModule : IModule
{
IUnityContainer _container;
public MyModule(IunityContainer container)
{
_container = container ;
}
public void Initialize()
{
9

_container.RegisterType<IMenuBarView, MenuBarView>();
_container.RegisterType<IMenuBarViewModel, MenuBarViewModel>();
}
}
Now, if you will run your application, you will still get an empty Shell. This is because, we havent composed our view yet.

View Composition
View Composition is the process of constructing a view. View consists of many visual elements. As and when these elements will
be created, Views will be displayed in the Regions, created by Shell. These items can be displayed using automatic View
Discovery or by using View Injection.

View Discovery
With View Discovery, views are added to Regions automatically. To enable View Discovery, we need to set a relationship in the
Region-View registry between a regions name and a type of view. To do this, one can simply call the
RegionManager.RegisterViewWithRegion(name, type). Typically this is done, when a Module initializes or
when user performs an action. When the Region is created, it looks for all the view types that are associated with the Region and
automatically instantiates those views.
A side-effect of this behaviour is that we dont have explicit control of when to load and display a view inside a Region.
Sample code for View Discovery
Lets open our MyModule class and add the following code:
public class MyModule : IModule
{
IUnityContainer _container;
IRegionManager _manager;
public MyModule(IUnityContainer container, IRegionManager manager)
{
_container = container ;
_manager = manager;
}
public void Initialize()
{
_container.RegisterType<IMenuBarView, MenuBarView>();
_container.RegisterType<IMenuBarViewModel, MenuBarViewModel>();
_manager.RegisterViewWithRegion(RegionNames.MenuBarRegion, typeof(MenuBarView));}
}
Now, whenever the Region is created, the Region will automatically initialize and instantiate our MenuBar item. Now at this
point, if you will run this, you will see your MenuBarView in Shell.
Here, we have very limited control on how and when MenuBar is initialize and instantiated.
View Injection
With View Injection, views are added programmatically to the Region. This can also be done, when a Module initializes or as a
result of user interaction. One can achieve View Injection by couple of different ways. This can be done by calling
RegionManager.Region[Name].Add(view, name) or we can get an instance of an IRegion from a

RegionManager and then work with the Region directly as IRegion.Add(view, name).
Please keep in mind that while programmatically adding views, one need to activate/deactivate views. For example, if your
content control has a Region, which already contains a view and if you add a new view to it, you need to deactivate the current
view for the newly injected view to show.
So, as we can see View Injection gives us more control over views to be loaded and display. We can also remove views from the
Region.
One thing to keep in mind with View Injection is that you cant add a View to Region that has not been created. For View
Discovery, view is automatically created when a Region is created. So, one should be aware of what all Regions have been
10

created, before you try to inject a view into it.

Sample code for View Injection


Lets again open our MyModule class and add the following code:
public class MyModule : IModule
{
IUnityContainer _container;
IRegionManager _manager;
public MyModule(IUnityContainer container, IRegionManager manager)
{
_container = container ;
_manager = manager;
}
public void Initialize()
{
_container.RegisterType<IMenuBarView, MenuBarView>();
_container.RegisterType<IMenuBarViewModel, MenuBarViewModel>();
var viewModel = _container.Resolve<IMenuBarViewModel>();
_manager.Regions[RegionNames.MenuBarRegion].Add(viewModel.View);
}
}
Now, run the application, you will be see your MenuBar view. Sometimes, we need a more control of the Region and in that
case, we can get instance of the Region using IRegion as:

11

Background
In earlier articles of this series, I already mentioned that Prism is all about loose coupling and modularity. So, in order to achieve
both these aspects we divide our application into multiple modules. Now, when we are talking about modularity, first thing
which strikes to our mind is communication. How will these module going to talk with each other, how they are going to
communicate with each other, etc, etc. So, when we have a need of communication between modules, there are couple of
approaches which we can take like Commanding, Event Aggregation, Shared Services, Region Context and probably there are
many more. In this article, mainly I'll be taking these four concepts:
Commanding
Event Aggregation
Region Context

Shared Services

Now let's take one-by-one and see, how they make our application loose coupled

Commands/Commanding Overview
This is the most common method of communication in Prism application. Now again, commanding is not specific to Prism
library. It is similar to what we have in WPF and Silverlight. Main purpose of commanding is to bind a UI gesture (i.e. a button
click) to an action which needs to be performed. Each command has an Execute method and this method is called whenever a
command is to be execute. Apart fromExecute method, command also has an CanExecute method, which determines whether
or not a command can be execute. An element that is bind to the command can be either enable or disable based on the result
of CanExecute method.
Most common ways to create command is either to use the RoutedCommand or Custom Command. RoutedCommand
delivers the command messages to UI element. On the other hand, Custom Command can be implemented by creating a
custom class, which in turns inherits an ICommand interface. Using custom command needs a lot of extra work and one has to
provide command handlers to hook off and then do the routing, when the command is on board.
Please note, in Prism application, command handlers doesn't have any association with any elements in the visual tree. But don't
get panic. Fortunately, Prism provides us with two classes that makes commanding more easier and provides more functionality.
It provides DelegateCommand and CompositeCommand.
A DelegateCommand is a command that allows you to call a delegate when the command is executed whereas
CompositeCommand allows us to combine multiple commands.

DelegateCommand
A DelegateCommand is a command that allows you to supply methods as delegates and will be invoked when the command is
invoked. So, this means that event handler is not at all required in the code behind. Another good thing is DelegateCommands
are normally stored locally means that are created in ViewModeland the concerns of the delegate methods are within the
context of that ViewModel. Now agian, Prism has something for these DelegateCommands. Prism actually provide you with two
DelegateCommand as DelegateCommand and DelegateCommand<T>. The difference is the Execute and
CanExecutedelegate methods for DelegateCommand will not accept the parameter whereas the DelegateCommand<T> allows
you to specify the type of parameter that Execute and CanExecute parameter can be. Now, let's jump into some code:

Using the code


Before getting into much depth, first I want to tell you about what I want to achieve here.

12

Now what I want is, whenever I click on Calculate button, interest amount should be calculated. So, let's go ahead and
implement this.
We know that calculate command should be executed on button click. So, we have to add below line of code for Button as
<Button Content="Calculate" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Command="
{Binding CalculateInterestCommand}" />
As of now this command doesn't exist in our ViewModel. So, let's go ahead and add this in our ViewModel as:
public ICommand CalculateInterestCommand { get; private set; }
Now we need to create an instance of this command. So, in the constructor add this line:
public InterestCalculatorViewModel()
{
CalculateInterestCommand = new DelegateCommand(Calculate, () => CanCalculate);
}
In the above command, first parameter will be the Execute method(in our case, it is Calculate method) which will be called when
a command will executeand the next parameter will beCanExecute(in our case, it isCanCalculate), which will tell whether a
command can execute.
Now go ahead and create your Execute and CanExecute parts as:
private void Calculate()
{
InterestAmount = PrincipalAmount * InterestRate / 100;
}
private bool CanCalculate
{
get
{
// you can add your condition to enable or disable the button
return true;
}
}
Run the application and you are all done. Isn't it very easy ??? Well, now quickly move on to the CompositeCommand.

CompositeCommand
These are the commands which are globally scoped and exists in the common portion(in our case it will be in Infrastructure
project) of our appand contains multiple child commands. These commands can be used where we have a requirement to
perform same logic on multiple viewswith single command (in our case, let's assume we have a tab control and on each tab I
am calculating interest amount). In that case, each view will have the local command bind in the ViewModel registered witha
CompositeCommand. So, whenever CalculateAllcommand is invoked, all the child commands will also be invoked. Similarly even
if single child's CanExecute returns false, CalculateAll will not be invoked.
For the demonstration of CompositeCommand, first let's open Shell.xaml. In Shell, I have added a another region, which contains
CalculateAll button. We also added a TabControl, in order to inject the multiple instances of a view. Your Shell.xaml will look like
this:
13

Then I've modified InterestCalculatorModule.cs to create multiple instances of view as:


At this point of time, if you will launch your application and click on CalculateAll button, you need to click the button three
times, as one more each view. So, to make CalculateAll work in proper manner, let's add a new class named
CompositeCommands as:
public class CompositeCommands
{
public static readonly CompositeCommand CalculateAllCommand = new CompositeCommand();
}
Now go to CalculateAllModule and open CalculateAllView.xaml and add the reference of Infrastructure project as:
<UserControl x:Class="CalculateAllModule.Views.CalculateAllView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:PrismDemo.Infrastructure;assembly=PrismDemo.Infrastructure"
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">
<Button Command="{x:Static cc:CompositeCommands.CalculateAllCommand}" Content="Calculate All"/>
</UserControl>
Now next step is to register our ViewModel for this CompositeCommand. Open the constructor of our ViewModel and add
below line:
CompositeCommands.CalculateAllCommand.RegisterCommand(CalculateInterestCommand);
Now launch the application and it will work as expected. Just clicking the button CalculateAll button, all the view will get their
calculation done.

EventAggregation Overview
This is the one of the common pattern, which is specific to Prism. EventAggregation provides event based communication in a
very loosely coupled manner. It is made up of Publishers and Subscribers. Here a publisher will execute an event and a
subscriber will listen to the event. Please note, subscribers do not need have any strong references to publishers.
Prism has built-in support for EventAggregation as it provides a core service by IEventAggregator interface. EventAggregator is
responsible for locating and loading the events. It is also responsible for keeping the collection of events in the system. Please
remember, publisher and subscribers will need an instance of an EventAggregatorand to get that event and for performing this,
they need help of container. EventAggregator also provides multicast Pub/Sub functionality means there can be multiple
publishers which raise the same event and multiple subscriberslistening to that event.
Events created using Prism library are typed events, which means compile time checking is possible, before we launch an
application. Prism provides a class named CompositePresentationEvent<T> to create such events. This class maintains the list
of all the subscribers and handles everything related to dispatching events. Please note, this is a generic class, so we need to
mention the payload type T. Here T is what we want to send to subsciber, when a event is published. EventAggregator provides
us with few services as:
Publication of events - by using Publish method
Subscribing events - by using Subscribe method
Subscribe using a strong reference - by using keepSubscriberReferenceAlive parameter on subscribe method. Please be
cautious while using this because while using this you manually have to unsubscribe from the event, when closing the
subscriber
Filtering events - by using filter delegate while subscribing
Unsubscribing events - by using UnSubscribe method
Now, let's jump back to code once again. Here our requirement is, whenever a calculation is completed, user should get a
message on statusbar indicating completetion of a calculation. Now to accomplish this, let's add a new class named
UpdateCalculationStatusEvent as:
public class UpdateCalculationStatusEvent:CompositePresentationEvent<String>
{
}
14

Now we need to write a publisher event in our ViewModel. So, add an instance of IEventAggregator and pass it to the
constructor of our ViewModel as:
IEventAggregator mEventAggregator;
public InterestCalculatorViewModel(IInterestCalculatorView view,IEventAggregator eventAggregator)
{
this.mEventAggregator=eventAggregator;
}
Now when a Calculate button is clicked, we want to send a message to the statusbar. So, in order to achieve that, we need to
modify our Calculate method as:
private void Calculate() {
InterestAmount = PrincipalAmount * InterestRate / 100;
mEventAggregator.GetEvent<UpdateCalculationStatusEvent>().Publish(String.Format("Interest amount
is {0}", InterestAmount));
}
As per the above line of code, whenever the Calculate method is executed, result will be published as 'Interest amount is so and
so'.
Now, next we need to create a subscriber for this event and here subscriber is going to be a StatusBar. So, let's open up our
StatusBar ViewModel as follows:
public class StatusBarViewModel : ViewModelBase,IStatusBarViewModel
{
IEventAggregator mEventAggregator;
public StatusBarViewModel(IStatusBarViewModel view, IEventAggregator eventAggregator)
:base(view)
{
mEventAggregator = eventAggregator;
mEventAggregator.GetEvent<UpdateCalculationStatusEvent>().Subscribe(CalculationCompleted);
}
private string message;
public string Message
{
get { return message; }
set
{
message = value;
OnPropertyChanged("Message");
}
}
private void CalculationCompleted(Object obj)
{
Message = "Updated";
}
}
Now let's go ahead and run our application and you are done

" />

Shared Servcies
Shared services is the another way of communication in Prism application. It is a custom classthat provides functionality to other
modules in a very loosely coupled way. This service is generally placed in aseparatemoduleand can be registered using a
Service Locator. When we register our service, it is registered as a common interface. This allows other modules to use our
servicewith acquiring a static reference to the module.But there is a side effect of using this common interface is that the
concrete implementation don't have to be shared. Registering your service as a shared service is very easy and can be done by
ContainerControlledLifetimeManager.

15

Region Context
Sometimes there arescenarioswhere we have to share contextual information between a view that is hosting a regionand a
view that is inside the region. For example, you may have a master detail type scenario where you have an orders view, which
exposes a regionto show the order detail information. To support this scenario, Prism providesRegion Context. By using
Region Context one canshare an object between the parent view and the child view that are hosted in the region.
Pleasenote, Prism only supportsconsuming the Region Contextfrom a view inside a regiononly if the view is a dependency
object. So, if your view is not a dependency object, then you need to create a custom region behavior. One important thing to
note here is do not use datacontext here, because datacontext is mainly use to bind viewmodel to a view. So, this means,
thatdatacontext is storing view's entire viewmodel. So, until and unless, we have very simple view, it is not recommended to use
datacontext for cummunicating loosely coupled views.

16

Anda mungkin juga menyukai