My diary of software development

Posts tagged ‘WPF’

Binding updates to a WPF View from outside of its ViewModel – part 1

Application Overview

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:

MVVM Class Interactions

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:

Triggering The ViewModel's PropertyChange Events

Triggering The ViewModel's PropertyChange Events

Keeping the view from becoming unresponsive

The next problem was that the PropertyChange events were happening so fast due to the the high rate of activity by the background threads that the UI became unresponsive. I solved this problem by only sending the PropertyChange events periodically (but often enough to keep the view continuously updated.) The image below shows the UpdateUI method which does this:
The UpdateUI Method

Summary

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.

Advertisements

A New Way To Hide Disabled WPF TreeView Items

I had a project with a strange requirement which dealt with hiding disabled items on a WPF tree view. The easiest way to for me to explain this requirement is to show it to you visually rather than try to explain it in words. First, take a look at the the image below, it is of a tree view with both enabled and disabled items:

Before

Tree View Showing Enabled and Disabled Items

The strange requirement which I was having difficulty with was to hide those inactive items but still leave their active descendants visible. Notice that item 1 is disabled but it’s direct descendant item 1.1 is not.  So to corectly implement this requirement, I would need to hide the parent item 1 but leave its child item 1.1 still visible. And not only leave its child still visible but leave its child’s horizontal positioning intact as well.

Below is an image of this requirement in action. All inactive items are hidden but their active children are not. If an active item was horizontally aligned X number of device units to the right when its inactive parent was visible, then it needed to stay horizontally alligned X number of device units to the right when its inactive parent was hidden.

After

Tree View Showing Only Active Items

I was writing this project using the MVVM pattern and so in my first attempt at this requirement, I simply used some data triggers in my XAML to hide items which were marked inactive in my view model. Walla! I was done and could move onto more pressing issues in the project. But I soon realized that was not going to happen because although I was able to easily hide inactive tree view items, their children were hidden also.  The default TreeView action when hiding an item was to hide that item’s children also regardless of if the children are active or not.

In order to solve this problem and implement my requriement correctly, I knew I’d have to probably look at the TreeView’s control template and modify it. Which I was dreading. I am not a XAML expert and wanted no part with doing something like this. As a matter of fact, I was quite confused by all of those ‘templates’ in WPF I kept hearing about and trying to read about. There is a control template, a data template, an items panel template, and others. I was thinking to myself, just how many templates are there any way? Do we actually need them? Come on Microsoft, make something easy for me for once.

So after I got over my rant, which took weeks, I took the time to sit down and tell myself “I am going to do this. It will be my project for the day and I can do this.” I felt the ‘force’ close by (well actually Josh Smith’s blog but close enough) and so I felt confident.

Isn’t it strange that after you do something which had been challenging you and forcing you to struggle to surmount it, that it really doesn’t seem so difficult after you do it? I hate that feeling, it makes me feel like I didn’t do anything. Nevertheless, I am going to present the very few and simple steps that I did to accomplish this daring and heroic feat :

1 – I pulled the TreeView control template with the Show Me The Template tool and copied it into my build directory to a new file named TreeViewForStrangeRequirement.xaml.

2 – I then placed a TreeView in my window’s XAML and referenced this new template:

XAML1

3- I had a checkbox on my window which the user could check to show only the active tree view items or the user could uncheck it to show all active and inactive tree view items.

4- I modified the control template at line 139 and added a MultiDataTrigger which triggered on this checkbox and on my view model’s IsActive property for each data item. The image below shows this section of the TreeView’s control template which I modified: 

 
 
 
 
 

Template

Section of the TreeView Control Template which I modified