Click here to Skip to main content
15,886,806 members
Articles / Desktop Programming / WPF

Virtualizing Tree View (VTreeView)

Rate me:
Please Sign up or sign in to vote.
3.81/5 (16 votes)
20 Jun 2008CPOL4 min read 63.2K   1.9K   29   8
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)


Written By
Software Developer Zyto
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseThis saved my bacon Pin
nishanh10-May-17 6:34
nishanh10-May-17 6:34 
PraiseThanks. Pin
xhy20115-Dec-15 20:27
xhy20115-Dec-15 20:27 
QuestionLearn, Thanks. Pin
xhy20115-Dec-15 20:27
xhy20115-Dec-15 20:27 
GeneralMy vote of 1 Pin
Shiva Chaurasiya20-Apr-12 22:17
Shiva Chaurasiya20-Apr-12 22:17 
QuestionImprovements Pin
arolson10110-Nov-11 7:09
arolson10110-Nov-11 7:09 
I've started to use this code in a project and have come up with some improvements:

* I changed the abstract base class (TreeNode) into an interface. (The VTreeView/TreeData code needs to be changed to just use the interface)
C#
public interface IVTreeNode : INotifyPropertyChanged
{
    int Level { get; set; }
    bool IsExpanded { get; set; }
    ICollection<IVTreeNode> Children { get; }
    bool HasChildren { get; }
    string Name { get; }
    void UpdateChildren();
}


* I changed the ItemTemplate to use a ContentPresenter so that you can create DataTemplates to customize display of your node. Without a DataTemplate it will display a TextBlock with the result of the ToString() method.
HTML
                        <Grid x:Name="myGrid" Width="Auto" Height="Auto" >
                            <ContentPresenter x:Name="myTextBlock" Content="{Binding}" HorizontalAlignment="Left" Width="Auto" VerticalAlignment="Center" Margin="2,2,2,2" />
			</Grid>
...
                            <Setter Property="TextBlock.Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" TargetName="myTextBlock" />


Now you can define a DataTemplates resource to display however you want, without losing the indentation/ToggleButton stuff:
HTML
<vt:VTreeView x:Name="VTree" Grid.Row="1" ScrollViewer.HorizontalScrollBarVisibility="Visible">
    <vt:VTreeView.Resources>
        <DataTemplate DataType="{x:Type local:MyData}">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </vt:VTreeView.Resources>
</vt:VTreeView>

GeneralGood job man [modified] Pin
Sacha Barber21-Jun-08 1:51
Sacha Barber21-Jun-08 1:51 
GeneralRe: Good job man [modified] Pin
Paul D Dickinson21-Jun-08 5:34
Paul D Dickinson21-Jun-08 5:34 
GeneralRe: Good job man Pin
Sacha Barber21-Jun-08 7:36
Sacha Barber21-Jun-08 7:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.