This articles explores the problems of standard WPF TreeView controls and describes a better way to display hierarchical data using a custom TreeListView control.
Background of TreeView
TreeView has quite a limited functionality and provides no easy way to extend it. WPF
TreeView seems like a major step forward, at first glance. But in real application the lack of features like multiselection or multicolumn view become apparent. Moreover, things that were quite easy to do in Windows Forms are now much more complex in WPF because there's no simple way to get the container item for your business object displayed in the
TreeView. For example, if you need to expand the currently selected node you have to use
ItemContainerGenerator as described here or use a special model just to support selection/expanding (see here).
Another weakness of the WPF
TreeView is poor performance. It takes more the 10 seconds to expand a node containing 5000 subnodes! Even navigation becomes very slow — more than a second to just move a focus.
But there is an alternative way to display hierarchical data — use the
ListView. The basic idea is the following:
For each tree node we create a row in the
ListViewItem template contains a special control named
RowExpander which allows you to expand/collapse a node and any number of additional controls to represent the data. Those controls are shifted to the right depending on the Node level.
When the TreeNode is expanded/collapsed we need to add/remove rows to/from the
Using this approach we get all the benefits from ListView: multiselection, a possibility to display several columns, performance improvements comparing to
TreeView, less memory usage because of virtualization support (it means that visual elements will be created only for the items currently displayed on the screen).
WPF TreeView is supposed to be used with
HierarchicalDataTemplate where you specify a property containing child items. It's quite simple, but requires you to provide such a property in your business objects, which means that you can't display the hierarchy of simple types, like String, in the
TreeView. Additionally, I prefer to use another approach — use a special interface which describes hierarchical data:
public interface ITreeModel
IEnumerable GetChildren(object parent);
bool HasChildren(object parent);
HasChildren method is used to display/hide the expander control without calling
GetChildren, which can be time expensive. Note that items are loaded on demand in TreeListView, which means the
GetChildren method will be called only when the corresponding parent node expands.
We create subclasses of
public class TreeList: ListView
internal ObservableCollectionAdv Rows
protected override DependencyObject GetContainerForItemOverride()
return new TreeListItem();
protected override bool IsItemItsOwnContainerOverride(object item)
return item is TreeListItem;
When the Aaren node is collapsed/expanded we need to insert/remove all child nodes and notify
ListView about that. As the system class
ObservableCollection doesn't provide methods for that we need to create our own collection class:
public class ObservableCollectionAdv : ObservableCollection
public void RemoveRange(int index, int count)
var items = this.Items as List;
public void InsertRange(int index, IEnumerable collection)
var items = this.Items as List;
For every item created by the model we create a
TreeNode class which will store node status (
IsExpanded) and track changes in the model if it provides such information:
void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
if (e.NewItems != null)
int index = e.NewStartingIndex;
int rowIndex = Tree.Rows.IndexOf(this);
foreach (object obj in e.NewItems)
Tree.InsertNewNode(this, obj, rowIndex, index);
if (Children.Count > e.OldStartingIndex)
while (Children.Count > 0)
HasChildren = Children.Count > 0;
Using the Code
The source code of the article contains two examples using
TreeListView. One uses a classic TreeView style and the other displays how to interact with the
TreeListView. The other shows how several columns can be used to display system registry.
Points of Interest
In the current implementation of the
TreeListView you have to keep the XAML markup of the
TreeListItem in the client library. Which means that you have to copy it to each project using the control. Normally this information should be stored in the same library as the control itself, but it just didn't work this way. If somebody finds the way how to achieve this, don't hesitate to share it.