Click here to Skip to main content
15,888,351 members
Articles / Mobile Apps / Windows Phone 7

Windows Phone 7 DeferredLoadContentControl

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
24 May 2011CPOL3 min read 12.2K   3  
A simple content control that can be used to defer the rendering of its contents in order to provide a better user experience on Windows Phone 7

This blog post describes a simple content control that can be used to defer the rendering of its contents in order to provide a better user experience on Windows Phone 7.

I think anyone who has made the transition from Emulator to Hardware with developing for Windows Phone 7 has experienced the same performance headaches. A couple of areas where performance hits hard is the rendering of ListBoxes and Images downloaded from the web. Thankfully, there are a number of blog posts describing a variety of ways to mitigate the problem. The ListBox performance tips page on the Silverlight WP7 team blog provides links to many useful resources on this topic.

The bottom line is that real WP7 devices take quite a bit longer to render the visual tree, and as developers we have to work around that.

One area in which I think the user experience really suffers is when the user navigates to a new page. If the page contains a reasonably complex UI (perhaps a list of 100 items), it can take quite a long time for the new page to appear. This gives the impression that the phone has locked up and become unresponsive (which I guess it has to a certain extent!). The guys at Telerik noted that using the Panorama control caused a load time of ~1.6 seconds. Whilst the splash screen will be displayed when your application initially loads, giving the user a feeling that the phone is doing something, subsequent page navigations lack any visual cue to indicate that the phone is doing something and hasn’t just died!

DeferredLoadContentControl

The DeferredLoadContentControl provides a simple solution to this problem, the content that is placed within this control is initially hidden by setting its Visibility to Collapsed. Elements that are collapsed do not occupy any layout space, and hence if an element with a long ‘render’ time is collapsed, this time is no longer consumed. When the DeferredLoadContentControl is initially loaded, it displays a ‘loading…’ indicator, then sets the visibility of its contents to Visible. When the content is rendered, the loading indicator is hidden.

The images below compare the user experience with and without the DeferredLoadContentControl:

Image 1

Image 2

Whilst this control does not make the page load any quicker, and the phone cannot be interacted with whilst the content is loading, it does mean that the page itself loads much more quickly and hence gives the user the impression that the phone is more responsive.

The code for the DeferredLoadContentControl is a very simple extension of ContentControl. The template for this control is shown below:

XML
<Style TargetType="local:DeferredLoadContentControl">
  <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
  <Setter Property="verticalContentAlignment" Value="Stretch"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:DeferredLoadContentControl">
        <Grid>            
          <ContentPresenter  x:Name="contentPresenter"
                       Content="{TemplateBinding Content}"
                       ContentTemplate="{TemplateBinding ContentTemplate}"
                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                       Margin="{TemplateBinding Padding}"/>
          <TextBlock x:Name="loadingIndicator"
                      Text="Loading ..."
                      VerticalAlignment="Top" HorizontalAlignment="Right"/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

The template contains a ContentPresenter which is responsible for displaying the controls content, and a TextBlock which displays a discrete message while the content is loading. You can of course re-template this control to add a graphical loading indicator, as long as your element has the name "loadingIndicator" it will be shown / hidden.

The code is also quite simple, here it is in its entirety:

C#
public class DeferredLoadContentControl : ContentControl
{
  private ContentPresenter _contentPresenter;
 
  private FrameworkElement _loadingIndicator;
 
 
  public DeferredLoadContentControl()
  {
    this.DefaultStyleKey = typeof(DeferredLoadContentControl);
 
    if (!DesignerProperties.IsInDesignTool)
    {
      this.Loaded += DeferredLoadContentControl_Loaded;
    }
  }
 
  public override void OnApplyTemplate()
  {
    base.OnApplyTemplate();
 
    _contentPresenter = this.GetTemplateChild("contentPresenter") as ContentPresenter;
    _loadingIndicator = this.GetTemplateChild("loadingIndicator") as FrameworkElement;
 
    if (!DesignerProperties.IsInDesignTool)
    {
      _contentPresenter.Visibility = Visibility.Collapsed;
    }
    else
    {
      // in design-mode show the contents 'grayed out'
      _contentPresenter.Opacity = 0.5;
    }
  }
 
  private void DeferredLoadContentControl_Loaded(object sender, RoutedEventArgs e)
  {
    // content has loaded, now show our content presenter
    _contentPresenter.Visibility = Visibility.Visible;
    _contentPresenter.LayoutUpdated += ContentPresenter_LayoutUpdated;
  }
 
  private void ContentPresenter_LayoutUpdated(object sender, EventArgs e)
  {
    // the content presenter has been rendered, hide the loading indicator
    _contentPresenter.LayoutUpdated -= ContentPresenter_LayoutUpdated;
    _loadingIndicator.Visibility = Visibility.Collapsed;
  }    
}

As you can see from the above, the content presenter is initially hidden, when the loaded event is fired, the content is shown. When the LayoutUpdated event is fired, we know that the content has now been rendered and hide the loading indicator.

Using the control couldn’t be simpler. Just place your slow-to-load content inside the DeferredLoadContentControl:

XML
<local:DeferredLoadContentControl>
  ... your content goes here ...
</local:DeferredLoadContentControl>

One nice feature of this control is that when used within the designer, the content contained within the DeferredLoadContentControl is not hidden, instead it is rendered with a 50% and the loading indicator is shown:

Image 3

You can download the full source code for this control here.

Regards,
Colin E.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Scott Logic
United Kingdom United Kingdom
I am CTO at ShinobiControls, a team of iOS developers who are carefully crafting iOS charts, grids and controls for making your applications awesome.

I am a Technical Architect for Visiblox which have developed the world's fastest WPF / Silverlight and WP7 charts.

I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.

Visit my blog - Colin Eberhardt's Adventures in .NET.

Follow me on Twitter - @ColinEberhardt

-

Comments and Discussions

 
-- There are no messages in this forum --