Hands up if you have ever built a highly interactive WPF application! I feel your pain. 🙂
Typically, in Banking the traders want to have all relevant information required for their day-to-day business compactly presented in very few or only one screen(s). This becomes challenging when the individual components are interactive, need to be up-to-date and can potentially be presented in multiple screens/tabs.
In one of my projects we faced the situation where out of a view model object graph messages had to be published to other view models in order to inform about certain events triggered by the user. The problem we had to solve was that the published messages had to be sent to all subscribes outside the view model object graph where the message originates from.
In the diagram below you see a set of object graph instances. The root object, PortfolioViewModel, sends and receives (RS) messages of type T and the DetailViewModel only receives (R) messages of the same type. The difficulty here is to make sure that the message is handled only by the subscribers that reside outside the object graph VM where the message originates from.
Typically, pub/sub messengers that come along with many MVVM frameworks do not provide information about the publisher. Even if, it would be difficult to find out whether the message has been sent by a VM within the same object graph.
An easy solution to solve that problem is to maintain a unique ID per object graph and send this information along with the published message. The subscriber needs to compare the ID of the origin against its own ID in order to know whether this message is relevant or not.
First we need a class representing the graph identity.
public class GraphIdentity : IGraphIdentity { private Guid _id = Guid.NewGuid(); public Guid Id => this._id; public bool IsItMe(IGraphIdentity id) { return this.Id == id.Id; } }
Now this is the crucial part. We need to ensure that the GraphIdentity instance exists only once per object graph. If you are using a dependency injection framework (like Unity for example), it’s fairly easy to do.
The Unity container below uses for each ViewModel class the TransientLifetimeManager, meaning that a new instance is created each time when the Resolve function is being called.
And for the GraphIdentity the PerResolveLifetimeManager ensures that only one instance of that type exists within an object graph that is being constructed per single Resolve call.
That means, you can inject the same GraphIdentity instance at any place within a complex object graph.
Container = new UnityContainer(); Container.RegisterType<IPortfolioViewModel, PortfolioViewModel>(); Container.RegisterType<ITradeViewModel, TradeViewModel>(); Container.RegisterType<IDetailViewModel, DetailViewModel>(); Container.RegisterType<IGuidelineViewModel, GuidelineViewModel>(); Container.RegisterType<IGraphIdentity, GraphIdentity>(new PerResolveLifetimeManager());
That’s it already. Now let’s test it by creating three instances of the PortfolioViewModel and publish a message from objectGraph1 to objectGraph2 and objectGraph3 instances.
ApplicationConfiguration.Init(); var objectGraph1 = ApplicationConfiguration.Container.Resolve<IPortfolioViewModel>(); var objectGraph2 = ApplicationConfiguration.Container.Resolve<IPortfolioViewModel>(); var objectGraph3 = ApplicationConfiguration.Container.Resolve<IPortfolioViewModel>(); objectGraph1.SayHiToOther("Hi to object graph 2 and 3!");
As a result, we can see below that i) the same identity has been injected in the root and _detailVm instances per object graph and ii) the message published by the method “SayHiToOther” has been handled by objectGraph2 and objectGraph3 instances but not objectGraph1.
If you have time, you could extend your pub/sub messenger and centralize that logic so messages are sent only to the respective subscribes. This would reduce some lines of code in your VM as you don’t have to compare the GraphIdentity in your subscriber method anymore. 😉