I’ve been working on an MVVM WPF app that has a view of metrics collected by some background threads. A screen shot is shown below:
As I mentioned, I’m using the MVVM pattern for this app so I have a view, a view model, and a model layer. The model layer consists of a ThreadMetrics class which contains the metrics you see for one row of the screen shot above. The view model (ingeniously named the ThreadMetricsViewModel) contains an instance of a ThreadMetrics class as well as the necessary get accessors for the view’s binding targets. The class layout and interactions are shown below:
Where this app starts to differ from the other MVVM apps I’ve written is that the updates to the view model’s data do not come from the UI user or a command handler inside the view model. Instead they start with a background thread which updates counts inside the ThreadMetrics instance within the ThreadMetricsViewModel. From there, the view binding will pick them up from Get accessors within the ThreadMetricsViewModel.
Since in this application, data is changed outside of the view model and needs to be reflected on the view, my problem became how to trigger the ThreadMetricsViewModel’s property changed events everytime the values in its associated ThreadMetrics instance were changed. There was also a problem with how often these values changed which caused the view to become unresponsive to user manipulations and I’ll cover that too.
Triggering view model property changes from the background thread
For the first problem of triggering the property changed events, I’m using the Mediator v2 solution which allows the ThreadMetrics instance to advise the ThreadMetricsViewModel of changes to its metric counts by the background thread. Each time the ThreadMetricsViewModel handles an update notification for one of these counts, it will issue a property changed event which causes the view binding to pick up that value and update it on the view. The image below shows the interaction which solved this problem:
Keeping the view from becoming unresponsive
So that is how I handled updating the view in my MVVM app from changes made outside of the view model, but I need to say that I still don’t get a ‘good’ gut feeling from this implementation. The ThreadMetricsViewModel doesn’t really serve any purpose other than being a go-between or a proxy to the ThreadMetrics instance which holds the actual values and the background thread class is where the actual logic takes place. It seems that there should be more logic in the ThreadMetricsViewModel, that maybe the ThreadMetrics class should go away and the background thread should reach into the ThreadMetricsViewModel instance to change values there. Or maybe that the ThreadMetrics and the background thread classes both should go away and all the thread and view model logic should occur inside the ThreadMetricsViewModel.
Causing a rift in the WPF coding space-time continuum
At the beginning of developing this app, I feared I may have caused a rift in the space-time continuum of WPF coding best practices because I did indeed have all of the thread/view model logic and data inside the ThreadMetricsViewModel instances. However this didn’t seem right either because I knew I was mixing backend service operations with view layer operations. It seemed that mixing everything like this into only two layers: the view and view model was violating some basic law of WPF coding best practices. I began to fear I had created an enormous rift in space and time so I refactored the logic into my current ThreadMetricsViewModel, ThreadMetrics, and background thread classes. Unfortunately it may already be too late and I’m writing this blog from another space-time realm of WPF development and do not know it.
My next post will talk about how I handled updating the aggregate metrics from all my ThreadMetrics instances. That is, the total number of Create and other operations.