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
.
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.
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))
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));
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()
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.
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.