Introduction
In this article we will learn about EventAggregator and IActiveAware interface and its uses in WPF application using Prism. This is continuation of second part of article series having total three parts.
In first part we have created Shell and defined the regions to load modules within regions of Shell. In second part we have created common infrastructure and five modules. So far we are able to load modules on application start as well as on demand and able to save request to database (xml file). As we have discussed in last section of second part, there is an issue with "All Request" module. In this part we will fix that issue and fulfill one more requirement.
Note: If you have not gone through first part and second part, I recommend you to first visit those because it will give you better context and help you to understand this article better.
Outlines
Part 1
- Overview of Final Demo
- Architecture of Final Demo
- What is Prism
- What is Shell
- Creating Shell and Defining Regions
Part 2
- Creating Common Infrastructure
- Creating Modules
- Navigation Module
- Employee Module
- Software Module
- Hardware Module
- Request Module
- Loading Modules
- Issues in Demo Application
Part 3
- What is Event Aggregator
- Use of Event Aggregator
- What is IActiveAware Interface
- Use of IActiveAware
Recap of the Issue
We left last demo application with an issue in "All Request" module discussed in last section of second part. Once "All Request" module is loaded for the first time, combobox is showing correct request Ids associated with entered Employee Id. But next time when Employee Id get change, combobox is not showing correct request Ids which are associated with latest Employee Id.
As per our requirement whenever Employee Id gets change, in "All Request" module combobox need to show all request Ids associated with recently entered Employee Id. To accomplish that we need to notify "All Request" module. This issue can be fixed with the help of EventAggregator.
What is EventAggregator
EventAggregator provides a global service to publish or subscribe events across application. EventAggregator is a class which implements IEventAggregator interface. It comes under "Microsoft.Practices.Prism.Events" namespace in Microsoft.Practices.Prism.dll. EventAggregator works as a mediator between publisher and subscriber objects for events. Whosever object wants to publish any event, need to communicate to EventAggregator by specifying parameter of event if any. Whosever object subscribes that event is notified by EventAggregator with published parameter (payload of event).
Following screenshot shows general pictorial description of EventAggregator with multiple publishers and subscribers.
In Demo application, EmployeeViewModel is playing role of publisher and RequestViewModel is playing role of subscriber. EventAggregator works as a mediator between EmployeeViewModel and RequestViewModel module. Following screenshot shows implementation of EventAggregator in Demo application:
How to Use EventAggregator
To use EventAggregator, there are some standard steps need to be followed. We will follow those steps in this section to use EventAggregator in order to fix the issue.
- First we need create a class inherited from "CompositePresentationEvent<TPayload>" that serve as event which we want to notify to different part of application. Already, in first part of the article series, we have added a class called EmployeeUpdatedEvent under Eventes folder in ITHelpDesk.Common.Infrastructure project. Typically such events are declared in a common project (here we have ITHelpDesk.Common.Infrastructure) because those events are supposed to be used in multiple projects in the application.
When we use EventAggregator with Prism based application then we get generic class called "CompositePresentationEvent". Since it is generic class so we need to provide a specific type. This type of message will be passed to the subscribers. So we have created EmployeeUpdatedEvent class and inherited by CompositePresentationEvent class. With EmployeeUpdatedEvent publisher (EmpoyeeViewModel) want to publish latest Employee Id which is an integer. So the parent class of EmployeeUpdatedEvent is CompositePresentationEvent which takes message (Payload of event) type as int.
public class EmployeeUpdatedEvent : CompositePresentationEvent<int> { }
EmpoyeeViewModel need to notify RequestViewModel whenever Employee Id gets change. For that EmpoyeeViewModel will publish an event called EmployeeUpdatedEvent with latest Employee Id.
- Publisher and Subscriber object must be using global EventAggregator provided by DI (Dependency Injection) Container. So here we will use EventAggregator provided by Unity Container and it is initialized in UnityBootstrapper class. This is out of the box and we need to look into the code of ConfigureContainer method of UnityBootstrapper class. Below is the code taken from open source Prism Library Code from Codeplex.
So creation of global EventAggregator is already done as our ITHelpDeskBootstrapper class inherits from UnityBootstrapper.
- EmpoyeeViewModel will act as a publisher so we need to inject EventAggregator object. Now in constructor of EmpoyeeViewModel we are injecting IEventAggregator and initializing a private field eventAggregator in constructor itself as shown below:
public EmployeeViewModel(IEmployeeService employeeService, IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.employeeService = employeeService;
}
- Employee Id needs to be published with updated value. So in the set block on "EmployeeId" property, we have added one line of code for publishing EmployeeUpdatedEvent after "if" block.
public int EmployeeId
{
get { return employeeId; }
set
{
if (value != 0)
{
employeeId = value;
fetchEmployeeDetail(employeeId);
RaisePropertyChanged("EmployeeId");
}
eventAggregator.GetEvent<EmployeeUpdatedEvent>().Publish(value);
}
}
Note: It is bit tricky to decide the right place for publishing and subscribing the event. To realize it, replace eventAggregator.GetEvent<EmployeeUpdatedEvent>().Publish(value); code at first line (just above if (value != 0) line) inside set block. Then we can see EventAggregator will not be helping us to fix the issue which we were facing.
- Any number of objects can subscribe published event (EmployeeUpdatedEvent). Let us see how to subscribe "EmployeeUpdatedEvent" event in RequestViewModel. In constructor of RequestViewModel we are subscribing for EmployeeUpdatedEvent. While subscribing we are passing a method (employeeUpdateHandler) which will be called when event will occur. In employeeUpdateHandler method we are calling fetchAllRequest method. As we can see from fetchAllRequest method, GetAllRequest method of EmployeeService is being called. Here we are getting updated empId in employeeUpdateHandler but we are not using it as we know that in EmployeeService, updated Employee Id will be available already. Below is the related code:
public RequestViewModel(IEmployeeService employeeService,IEventAggregator eventAggregator)
{
this.employeeService = employeeService;
this.eventAggregator = eventAggregator;
eventAggregator.GetEvent<EmployeeUpdatedEvent>().Subscribe(employeeUpdateHandler);
fetchAllRequest();
}
private void employeeUpdateHandler(int empId)
{
fetchAllRequest();
}
private void fetchAllRequest()
{
List<Request> listOfRequest = employeeService.GetAllRequest();
AllRequests = new ObservableCollection<Request>(listOfRequest);
}
GetAllRequest method of Employee service is calling GetAllRequest method of repository by passing CurrentEmployeeId.
public List<Request> GetAllRequest()
{
return dataSource.GetAllRequest(CurrentEmployeeId);
}
Now run the application and combobox will always show request Ids associated with Employee Id.
What is IActiveAware
IActiveAware is an interface which is used if we need to perform some action on Activation or Deactivation of a View. If we are following MVVM, we should implement this interface in corresponding ViewModel class.
This interface has two members: a property called as IsActive and an event IsActiveChanged:
public interface IActiveAware
{
bool IsActive { get; set; }
event EventHandler IsActiveChanged;
}
When the View or corresponding ViewModel, gets active or deactivate, RegionActiveAwareBehavior class sets the new value of IsActive. We can use IsActiveChanged event to notify interested parties about Active status change.
New Requirement: We will understand IActiveAware by implementing a new scenario. Let's say we get a requirement that when user revisits any module, its controls must be refreshed. Those controls should not be holding old values. Those must be empty while revisiting again.
As of now if we make some selection in Software Module, and then Navigate to other module and revisit Software Module again we will see the old selected values in controls. Below screenshot is having steps to highlight this behavior in the demo we have developed so far:
In next section we will implement IActiveAware to meet this new requirement.
How to Use IActiveAware
First we will implement IActiveAware interface in SoftwareViewModel class. In order to reset the controls, we need to set bound properties with default values. Let us inherit SoftwareViewModel with IActiveAware interface and provide the implementation as shown in below code. Here refreshSoftwareModule method is being called from set block of IsActive property. In this method we are setting bound properties with default values.
#region IActiveAware implementation
bool active;
public bool IsActive
{
get
{
return active;
}
set
{
if (active != value)
{
active = value;
if (active == true)
refreshSoftwareModule();
}
}
}
private void refreshSoftwareModule()
{
SelectedSoftwareCategory = null;
SelectedSoftwareName = null;
Comment = null;
}
public event EventHandler IsActiveChanged;
#endregion
Now run the application and follow the steps from 1 to 7 as per above screenshot. At 7th step we will see controls of Software Module are refreshed as per the given new requirement as shown below:
In similar way we can implement IActiveAware interface for Hardware Module also.
Conclusion
In this part of the article series, we learned about how to use EventAggregator and IActiveAware in the Prism application. This is last part of the article series, hope you will find this series helpful. Your comments/suggestions and queries are most welcome. Thanks.