Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Virtualizing Tree View (VTreeView)

3.81/5 (16 votes)
20 Jun 2008CPOL4 min read 1   1.9K  
Virtualizing Tree View a WPF custom control base on a ListBox

Introduction

This article discusses how to use my Virtualizing TreeView (or VTreeView). It also compares the performance and flexibility between WPF's TreeView and my VTreeView.

Background

I built a project that used the WPF treeview. I was impressed with the data binding and flexibility in styling the treeview. After I thought I was done, I found that the performance of the treeview was lacking. The performance issues are in part due to the amount of data (150 items on the main level and 100 under each of those) and the complexity of the style (each node had a custom icon) I was using. Loading my tree view took about 6 seconds. At first I thought the amount of time was long because each of the 150 nodes had to check its children to see if it should show the expander. At this point, I decided to try Philipp Sumi's extended treeview. I like Philipp's extension because it allows for data virtualization. I was able to override the HasChildItems and write a much faster method than the slow default of fetching all the children. This cut my load time down to about 3 seconds. But this still was not fast enough. I realized that the remaining 3 seconds were not related to the data but to the UI Elements. The TreeView does not virtualize its UI Elements. The only controls that do are the ones that use the virtualizing stack panel such as the listbox. I decided to Google a little more and I found Beatriz Costa's Tricks on improving the treeview's performance. After converting her code to use my business logic, my load time dropped to about 1/2 a second and the memory usage dropped by a factor of 10. You could say I found my answer. My only difficulty with her code was that it was hard to reuse because the treeview logic and the business logic were mixed into the same classes and the styles had to be copied. After all this, I decided to make a custom control that extends the listbox that would act and look like a treeview. I call it the VTreeView.

Using the Code

Data Binding

The first line is binding to a TreeView and second to a VTreeView:

C#
myTreeView.ItemsSource = root.Children;

myVTreeView.Data.AddRootItems(root.Children);

Binding to Children

The treeview uses HierarchicalDataTemplate. The VTreeView uses an abstract class call TreeNode. So instead of setting ItemsSource = "{Binding Path=Children}", the TreeNode can be extended overriding the Children property. Note how the overridden property uses a cached version of the TreeNode List. This is optional. I show this to emphasize the flexibility of extending the TreeNode class.

C#
private List<treenode> children = null;

public override ICollection<treenode> Children
{
    get
    {
        if (children == null)
            updateChildren();

        return children;
    }
}

private void updateChildren()
{
    children = new List<treenode>();

    for (int i = 0; i < 150; i++)
    {
        children.Add(new RandomTreeNode() { Name = i.ToString() });
    }
}

At this point, you are ready to use the VTreeView, but if you would like to further optimize the VTreeView and use some its added functionality, keep on reading.

Overriding the Name Property

If you decide to use the default template or a copy of it, you will need to override this property.

C#
private string _name = "";
public override string Name
{
    get { return _name; }
    set
    {
        _name = value;
    }
}

Overriding the HasChildren Property

This property is virtual so you don't have to override it. The default implementation just checks the count on the Children property. If checking the child count is slow, then you can override this method with something faster.

Overriding the UpdateChildren Method

This method is called if the VTreeView.Data.UpdateChildren(TreeNode TN) is called. This allows you to update entire collections and have it reflected in the tree. But if your tree is static, there is no need to override this method.

TreeNode IsExpanded Property

This property allows you to programmatically expand and collapse a node. It is used in the default data template to control the look of the expander.

TreeNode Level Property

It is used in the default data template to control the amount of indentation of the node. This is what really makes the ListBox look like a TreeView. I have to give credit to Beatriz for this one.

The VTreeView.Data is of Type TreeData. This class keeps the Tree Data bound to the ListBox and responds to node expansion and collapsing. This class can be used to add root items, remove items (and their descendants), and to send update children commands.

Added Bonus

VTreeView is extended from ListBox. This gives us the added bonus of all the selection modes including multiple select. SelectedItems and Items properties allow for easy selection control and searching for items.

Conclusion

Remember this is a custom control so you can use the default styles or replace them with your own. The VTreeView requires items of type TreeNode but you can mix and match different classes that extend TreeNode. For example, you could have a TeamTreeNode class whose children are of type PlayerTreeNode. Please give me feedback. I would really like to know if this article has been helpful. You may email me at paul@zyto.com.

History

  • 20th June, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)