Experiences with the WPF TreeView control

A few years ago, before C# existed, I wrote a Windows MFC C++ application to show how disk space was used. The output was a set of hierarchical folders (with size) , presented in a TreeView.

Old version of DiskUsage

To obtain some experience of C#, I decided to re-write the DiskUsage program and, at the same time, use another 'new' thing, the Windows Presentation Framework (WPF).

In the first attempt in C#, I used exactly the same technique to create the WPF TreeView contents as I had done with the MFC version. That is, the TreeView is populated by C# code in the OK button callback. There were a few hurdles to jump.

Hurdle 1 - Setting the Style of TreeViewItems to stop runtime errors

I'd subclassed TreeViewItem to add a Size attribute (to hold the folder/file size). Instances of this class were added to the TreeView programmatically, but this produced the runtime error:

  System.Windows.Data Error: 4 : Cannot find source for binding with
    reference 'RelativeSource FindAncestor, ...

To solve this prblem, in the constructor for SizedTreeViewItem, the style of the base class had to be added:

  this.SetResourceReference(StyleProperty, typeof(TreeViewItem))

Hurdle 2 - Sorting children in the TreeView

Sorting children of SizedTreeViewItem nodes in the TreeView required this magic incantation to be applied recursively from the root of the TreeView:

  tvi.Items.SortDescriptions.Add(new
    System.ComponentModel.SortDescription("Size",
    System.ComponentModel.ListSortDirection.Descending));

Hurdle 3 - Adding images using StackPanel

This solution used StackPanel to add both images (Image) and the file/folder name and size (Label). These were added to the StackPanel instance using

  Children.Add()

Hurdle 4 - No folder chooser dialog in WPF

There is a chooser dialog in System.Windows.Forms. (N.B WPF controls are in System.Windows.Controls). Implementing this chooser dialog must use the fully qualified name, i.e.

  System.Windows.Forms.FolderBrowserDialog FolderDialog = new
    System.Windows.Forms.FolderBrowserDialog();

This is because adding a using directive for System.Windows.Forms generates a large number of name clashes with System.Windows.Controls.

Thank you StackOverflow.

One problem remained. The population of the TreeView was dog-slow (around 20 to 30 seconds). What's worse, it was blocking the GUI thread. Experiments showed that the key time hog was adding images to the StackHeader used as the TreeViewItem header. Without them, the population time was more like three to four seconds. Still slow though. Was there a better way?

Some web searching took me to this helpful post, which gave me enough clues to re-write the code to fit the WPF TreeView model.

New version of DiskUsage

Performance is a lot better; the only slow part is the walk through the filesystem, as expected. The code is a lot cleaner, although I'm not sure I understand some the magic going on behind the scenes. The new DiskUsage2020 program can be downloaded from here.