August 15, 2014

LazyControl in JungleControls

LazyControl from JungleControls library is a clever WPF control that only materializes its contents when it becomes visible to the user. It is useful in large, complex layouts where traditional virtualizing panels won't do.

While WPF contains VirtualizingStackPanel and some infrastructure that allowed others to create other kinds of virtualizing panels, complex layouts have been so far impossible to virtualize. By complex layouts, I mean any scrollable list that includes grouping, multiple concatenated lists, scrolling headers/footers, and other features.

Layouts like this have been standard in HTML for two decades and browsers implemented them very efficiently. While WPF allowed us to create native apps with similar fancy layouts, the performance was never there. Microsoft's answer is virtualization, but it never worked for complex layouts. Now with LazyControl you can have HTML-like complex layout with decent performance.

<jc:LazyControl
    xmlns:jc="clr-namespace:JungleControls;assembly=JungleControls"
    Height="{Binding HeightHint}"
    Content="{Binding}"
    ContentTemplate="{StaticResource MyHeavyTemplate}" />

It looks like normal ContentControl at first glance. Notice the HeightHint binding. Since the content isn't materialized yet, it is impossible to calculate control size automatically. View models must supply precomputed height instead. Width might also be needed if default stretch behavior isn't desirable. This is the cost you pay for the optimization. Not a big deal in most applications as control dimensions are highly predictable.

LazyControl checks upon construction whether it is visible, i.e. whether it falls within visible region of nearest ancestor of type ScrollViewPresenter. If it is visible, it immediately instantiates ContentTemplate. If it isn't visible, it starts monitoring layout changes (event UIElement.LayoutUpdated). Whenever layout is updated, due to scrolling or for other reasons, LazyControl rechecks its visibility. The first time visibility is detected, LazyControl instantiates ContentTemplate.

There are some limitations. Currently container detection is not pluggable. ScrollViewPresenter is assumed to be in the visual tree. Collapsed/Hidden state of ancestors isn't taken into account when checking visibility. Effects and visual transforms have not been tested and their changes might be ignored if they don't raise LayoutUpdated event. Patches are welcome as usual.

You can get LazyControl from NuGet as part of JungleControls library.

No comments:

Post a Comment