Before you start reading – I have a new version of the TreeListBox available here
INTRO
Happy birthday to you, Happy birthday to you….. yahooooo today is my birthday!!! yes guys, it’s true today is my birthday and so yesterday I decided that I am going to give the developer side of me a birthday present!
I was thinking about this, when suddenly while having my daily bread (i.e reading the www.beacosta.com blog), I saw it ! the perfect birthday present, A Virtualizing TreeView Control!!!
UI Virtualization is really cool yet it is also complex. I had a chat with one of the best WPF developers I know Dr.WPF and he explained to me how complex it would be to have a VirtualizingStackPanel that understands hierarchies (have a look at the chat over here). As I already said this all started from the Beatriz Costa blog post, so I could just have used the same approach as beatriz (which by all means is good as the one I am using). But you know me, I like to build space shuttles (maybe even if it’s for nothing 🙂 ).
So there I was with my pen and paper, packet of ciggarettes, mug of pure coffee and my beloved laptop(aka ‘marlon-csharp’)…
The Basic Idea
The basic idea is to have a listbox that understands hierarchies and populates a flat list instead of using the hierarchal list approach… something like the following
Actual tree structure
0
child1 of 0
child2 of 0
1
child1 of 1
child2 of 1
where here the data items are in 3 seperate collection >>
1 for the main list (0, 1)
1 for the children of 0(child1 of 0, child2 of 0)
1 for the children of 1(child1 of 1, child2 of 1)
Flattened list
0child1 of 0
child2 of 0
1
child1 of 1
child2 of 1
on the other hand the flattened list would be one collection that contains all the items inside…
Basically the whole concept is to force the ItemsControl(which is our listbox) to stop from generating the Items by it self so that we can do it and set what ever values we want. If the ItemsControl thinks that it has a flat list BAMM you have it – Virtualization at last. Then it is just a matter of changing the look of the listbox to look like a treeview…
The Actual implementation
In order to implement the virtualization feature I simple extend the ListBox control with 2 new properties
ChildItemSourcePath –
This is basically a string that contains the name of the property exposing the collection of the children
Basically this is the Path you would enter for the binding of the HierarchalDataTemplate i.e
<HierarchalDataTemplate ItemsSource=”{Binding Path=Children}” …
transalates to
ChildItemSourcePath = “Children”
Basically this property is used so that by reflection we get the list that contains all children and populate them in the flattened list.
HierarchalItemsSource –
This property is just like the ItemsSource property yet when using the TreeListBox you must use this property for the data source, since this populates the ItemsSource by setting it to the internal flat list…
So if before you had this code in the tree view
ItemsSource = xList;
translate to
HierarchalItemsSource = xList;
Important – You should never use the ItemsSource property of the TreeListBox
——————————
Now the fun part begins……
int counter = 0;
foreach ( object item in newValue)
{
TreeListBoxItem listItem = new TreeListBoxItem (this, compositeChildCollection, 0);
this.PrepareContainerForItemInternal(listItem, item);
compositeChildCollection.Add(listItem);
counter++;
}
this.ItemsSource = compositeChildCollection;
This code snippet basically is the whole concept. We prepare the items for the ItemsControl(i.e the listbox that we inherit from). In this way we can add the level property and we can also pass the compositeChildCollection which is out flat list so that the children can add themselves to this list. Now the children do practically the same thing
//get the current index of the current item from the flattened list. this index is then used to insert the child item for this item in the appropiate index
int currentIndex = parent.ItemContainerGenerator.IndexFromContainer(this);
//create the item yet this this the level is the current level + 1
TreeListBoxItem listItem = new TreeListBoxItem(parent, compositeDataItems, level + 1);
//ask the parent (which is the TreeListBox) to preapare the actual item
parent.PrepareContainerForItemInternal(listItem, item);
//add the new item in the Children collection of the current item
childTreeListBoxItems.Add(listItem);
//add the newly created item to the flat list (childTreeListBoxItems). this is a very important part. here we insert the item in the appropiate index of the flattened list
compositeDataItems.Insert(currentIndex + lastItemCreatedIndex, listItem);
lastItemCreatedIndex++;
And this is basically how we add item and child items in the TreeListBox… Now how can we remove them. This is relativly easy…
//we pass the item to delete to the remove method and this will automatically get the correct index for the itemand remove the item from the flattened list
compositeDataItems.Remove(item);
I hope you are still with me because basically this is it… You will for sure understand more if you have a look at the actual code! This is what I call the TreeListBox which is basically a normal Listbox that thinks its a tree view 🙂I hope you find this control useful, please send as many feedback as you can….I guess you all know my email, if not this is it marlongrech@gmail.com, contact me if you need anything…Now I think I need some sleep !!!Best Regards
Download Source Code