I have a tree view representing certain items. This tree is always two levels deep. The right-click menu for the child items has a “move up” command. The UI allows you to move a child item up even if it’s the first item of its parent, as long as there is another item at the parent level, above the selected item’s parent.
The obvious way to do this is to get the selected item’s parent and see if there are items above it. However, getting the selected item’s parent in WPF is anything but trivial. Again, the obvious (for a WPF beginner, anyway) approach is to get the TreeViewItem for the selected item, which has a Parent property. Unfortunately, this is also hard to do.
Taking the hint from someone who says it’s hard because I’m doing it wrong, I decided to ask those more experienced with WPF: what’s the right, non-hard way to do this? Logically it’s trivial, but I can’t figure out the correct way to deal with the WPF APIs.
You are absolutely right that doing this kind of thing with the Wpf TreeView is painful. A key part of the reason for that is the flexibility that Wpf gives you – you could have overriden the ItemContainerGenerator in a custom TreeView and your tree view might not actually contain TreeViewItem objects, for example. i.e. there isn’t that same fixed hierarchy that you find in a comparable Winforms control.
It really seems counter intuitive at first and it’s a real shame that MS didn’t spend more time explaining how to make this kind of thing work in a way that doesn’t lead to frustration.
We’ve had huge success with Wpf since embracing MVVM – to the point where we always create a ViewModel for classes bound to the UI, without exception – it’s just that much easier to wire in new functionality later down the line.
If you have an underlying viewmodel (or even model item if you must) that your tree view is bound to, and think of the treeview as just an observer, you will get along much better with the Wpf TreeView and other Wpf controls too. In practical terms for a tree bound hierarchy, you would have a hierarchy of viewmodel objects that your TreeView is visualizing – where each child has a handle back to it’s parent, and each parent has a collection of child viewmodels. You would then have Hierarchical data template for each item, where the ItemsSource is the ChildCollection. You then fire off your “MoveUp” command against the ViewModel, and it takes care of making the change – if you are using collections based on ObservableCollection (or that implement INotifyCollectionChanged) then the TreeView updates automagically to reflect the new hierarchy.
Driving the functionality from the ViewModel, and seeing the UI as just a thin layer reflecting the ViewModel hierarchy and properties makes for code that can be unit tested to a high degree – with no code in the code-behind, you can often test your ViewModel functionality without any UI at all which makes for much better quality code in the long run.
The natural response for us when we started with Wpf was that ViewModels were overkill, but our experience (having started off without them in many places) is that they start paying off pretty rapidly in Wpf and are without doubt worth the extra effort to get your head around.
One thing you might not have hit yet, which we found really painful, was setting the selected item on a treeview – now that’s not something for the faint of heart 🙂