Reputation: 17556
A very intresting problem ( or design constraint) , i have encountered lately.
i was develping an application which is build using WPF/ Prism.
And one of the feature (very pressing client requirement) of this app is to open multiple duplicate views of a form ( say multiple customer entry forms). we are using MVVM pattern so we have multiple VM objects residing in memory.
Now one of our Service raises publishes event and our VMs subscribed it, so all the opened view models got the event notifications and statrs executing code.
now here lies our problem to restrict this and actually only that VM should start executing code which actually initiates the operation.
i think , this problem will be with normal events also and its actually doing the intended things to notify all listners.
we have put checks to identify which VM initiates the operation only that VM shd execute code after getting notification.
my question is , what should be the correct design in this very rare scenarion?
Upvotes: 1
Views: 482
Reputation: 132548
Usually I attach a parameter to the EventMessage which defines which ViewModel should handle the event. If that value can be null (meaning any VM can handle it), I often add a Handled
property to the EventMessage and the first ViewModel that handles the Event sets eventParams.Handled = true
For example, to publish an event to the same VM, I would use syntax like this:
// Publish for specific ViewModel
eventAggregator.GetEvent<MyMessage>().Publish(
new MyEventArgs { SpecifiedViewModel = this });
// Publish for any ViewModel
eventAggregator.GetEvent<MyMessage>().Publish(
new MyEventArgs());
To handle an event that should only be handled by one ViewModel, the code might look like this:
void HandleEvent(MyEventArgs e)
{
if ((SpecifiedViewModel == null && !(e.Handled))
|| (SpecifiedViewModel == this))
{
// Handle Event
e.Handled == true;
}
}
Upvotes: 1
Reputation: 1112
We have a simular scenario as you described, we solved this 'problem' to let the view which initiates the operation send an unique id (Guid) in the request, the background service which is responding to the request is sending besides the data the same unique id back.
The above scenario will able you to filter the events which are published by the background service by the event aggregator per view.
Guid referenceGuid = Guid.NewGuid();
//Subscribe to the futures events which are being published by the background service (filter per referenceGuid).
_eventAggregator.GetEvent<RetrieveMetricsResponseEvent>().Subscribe(ProcessUpdates, ThreadOption.BackgroundThread, true, response => response.ReferenceId == referenceGuid);
// Send the request to the background service
_eventAggregator.GetEvent<RetrieveMetricsRequestEvent>().Publish(new WrappedRetrieveMetricsRequest { MetricSourceID = configuration.StrategyInstanceCode, Identifier = configuration.SourceValueFieldName, ReferenceId = referenceGuid });
Upvotes: 2