Posts for Category: Performance

Virtualizing TreeView for Silverlight, with Diagrams

For large hierarchies the TreeView in the Silverlight tool-kit suffers some performance problems, because the elements (once loaded and expanded, such that they could be seen by the user if they scrolled the scroll-bar) aren’t virtualized as aggressively as they could be. The for example the hierarchy shown below: If Child Node 4 is expanded, pushing Child Node 5 outside the limits of the view port of the TreeView then Node 5, as well as any other children of Node 4 that aren’t directly visible, _could_ be virtualized but currently aren’t by the Silverlight Treeview. When the number of invisible-but-loaded nodes is small the performance impact is negligible, but if Node 4 (in the example below) had 10,000 children, each with a complex data template applied to them the performance impact expanding the tree can be quite noticeable.

silverlight tree view diagram one - collapsed and expanded nodes

One approach to get around this is to recognize that a TreeView is just a List with indentation and expand/collapse semantics. By flattening your object hierarchy with an appropriate wrapper you can use the virtualization that is built into the ListBox, which happily does virtualize items that have disappeared off the top or the bottom of the list, by virtue of its use of the VirtualizingStackPanel that was added in Silverlight 3.

 The sample provided does just that with two classes TreeViewModel<T> and NodeViewModel<T>. TreeViewModel<T> contains a Nodes collection, an ObservableCollection of NodeViewModel<T> which the list is bound to. The visibility of the expand/collapse arrow is bound to the presence of children. When a NodeViewModel<T> is expanded it calls back to the TreeViewModel<T> to tell the TreeViewModel to create a new set of NodeViewModels based on the children of the node being expanded, and to insert them directly after node being expanded in the current list of nodes. When the TreeViewModel makes new nodes it increments the indentation property, which is used to drive how far in the node is rendered when it is shown. When a NodeViewModel<T> is collapsed it again calls the TreeViewModel<T> and basically tells it to throw away all the nodes that come after me in the Nodes collection, until you reach one that has the same indentation as me (or you reach the end of the list), at which point the TreeViewModel will know that it has removed all the children of the item that was collapsed.
The sample provided is not a complete drop-in replacement for the TreeView control in the Silverlight toolkit. For one thing some of the expand/collapse semantics are a little different to a standard TreeView. For example if all the nodes in the tree are fully expanded, and the root node is collapsed and then re-expanded then the standard tree-view behaviour is for the tree to look the same as before the root node was collapsed, however this tree will only show the direct children of the root node after the root node is collapsed and then re-expanded, regardless of the state of the tree before. This is a side-effect of the way this implementation creates and destroys NodeViewModel<T> instances when a node is collapsed/expanded. When a NodeViewModel<T> is removed from the list of nodes the fact that it was previously expanded is lost. This could be changed by keeping instances of removed nodes around, but would complicate the expand/collapse methods in TreeViewModel<T>. Also some other TreeView standard keyboard short-cuts are missing (for example right arrow to expand a node, and left arrow to contract it) are not wired up. Also it is likely that this technique will become obsolete at some point when the TreeView in the Silverlight Toolkit catches up with the WPF one and implements this trick for itself.

Silverlight TreeView diagram 2 - class library

You can download the source code from here. And here is an image of the sample running.

Tee View Sample Running

posted on 6/24/2010 10:12:49 PM


Write Your Own Hardware Accelerated BitmapEffects - Coming soon to WPF

One of the interesting announcements that seemed to get lost in the flood of Silverlight news from Mix08 was a further information about future improvements to WPF. In his keynote talk Scott Guthrie re-iterated many of the things he'd detailed previously in the 3.5 client road-map. One slightly new bit of information was the opening up of BitmapEffects to people outside Microsoft. Not only that, you will be able to write hardware accelerated BitmapEffects! This means that DropShadow, Glow and Blur (some of the built-in effects) which are currently software rendered, and if used inadvisably can have nasty performance impacts will also be hardware accelerated.

During the keynote we were treated to a number of effects including ripple (see below) and fish-eye magnification.

Hardware accelerated ripple effect

posted on 3/11/2008 1:30:52 AM


Finding Memory Leaks in WPF Applications

Jossef  from the WPF Preformance Blog wrote a useful article about a month ago on diagnosing memory leaks in WPF applications. Although some of the issues shown are not WPF specific the leaks caused by command and data binding are. This article is well worth checking out if your perfromance testing seems to show a memory leak. 

posted on 3/3/2008 1:05:56 AM


Glossy Brushes using Radial Gradient Brush in WPF

I recently wanted to convert some nice glossy SVG-based shapes into WPF. Here is the result.

glossy rectangles

The original brushes came from here on the OpenClipart.org site.

I attempted to convert them using WPF 3D Graphics' SVG-XAML converter, however this proved unsatisfactory for 2 reasons: firstly there was a significant loss of fidelity in the conversion to SVG (which is unusual since the converter is pretty good), and secondly the conversion approach was to create lots of Shape-derived classes absolutely positioned in Canvas elements, so instead I ported and hand-tweaked the brushes. This class uses a serise of GeometryDrawings and should be quite light-weight on tier 2 graphics hardware. On tier 1 the story is a little different, since RadialGradientBrush is NOT hardware accelerated on these platforms. Although the converted brushes are simpler than the SVG originals (for example the slight "ripple" in the reflection line), I'm still pleased with the result as they do look nice.

Download the XAML file with theese brushes in them here

posted on 2/2/2008 12:01:22 AM


Real-World WPF Start Time Perf Tip - Delay Setting the DataContext

.NET applications traditionally suffer from slower startup time than native applications, caused by the time to load the .NET framework DLLs, JIT time etc. WPF applications have further things that can slow down cold start-time, the extra PresentationCore, PresentationFramework and WindowBase assemblies that need to be loaded and the start-up of the PresentationFontCache service. Any tips to help improve start time is therefore most welcome.

Doug Stockwell recently released an updated version (v1.6 build 2802) of his free RikReader WPF-based RSS Reader, with considerably-improved start time. I've been using RikReader as my primary RSS reader since it was first released, and in previous versions the start time stood out as a blemish on an otherwise excellent app. The performance characteristics of older versions of RikReader were a little different to usual applications, in that the hot start-times were still quite bad (>10 seconds for my list of a couple of hundred feeds), whereas the new version hot-starts in about 4 seconds (roughly equivalent to Expression Blend, Thoughtex and most other WPF applications I use). Cold start-times for RikReader had also improved noticeably.

I contacted Doug to find out what he'd done to achieve this great improvement, and was pleased to hear of the simple change he had made. Instead of using XAML to declaratively set the DataContext for his main window, which contained all the RSS feed data, he switched to setting it programmatically in the Application.OnActivated. This sounds like a tip that would improve the perceived performance of the app (making the main window display more quickly) without improving the actual performance, however it seems to have also improved the actual start time considerably. As with all things performance-related your mileage may vary, and it pays to measure yourself. Fortunately the simplicity of this change means it will be easy to swap between the two methods of setting the DataContext.

posted on 9/4/2007 4:46:17 AM