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:
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.
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:
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: