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