Silverlight for Windows Phone 7: ListBox Scroll Performance

Having a basic list scoll is a key scenario for many applications. The Silverlight Windows Phone 7 list box control makes it easy to bind data and get the performance benefits of UI container virtualization. However, in order to get these free performance benefits you need to be careful about how you use it.

Here are some tips on how to tweek your list box scroll performance.

Simplify ListBox Item

Listbox's VirtualizingStackPanel (VSP), calculates the height of items currently in the view and buffers the UI containers for a screens worth of items above and below what is currently in the view. This works great if the items are of fixed size. If you change the size of the items, the UI virtualization breaks and you don't get any performance benefits.

  • Ensure you have the item data template in a fixed sized container (grid).
  • Avoid/remove using complex converters, when the same information can be easily provided by the data object.
  • Avoid/remove nested structures, example listbox in a listbox item.
  • Strongly recommended to not use user control inside the data template.
  • Avoid/remove custom controls from the data template

Load the images in background

If you have refered to the performance document, you will know the importance of keeping the UI thread free for better responsiveness to handle input. This means that if you load the images on the UI thread, an input like flick might be lost. David talks about how to move the image loading to a single background thread in his blog LowProfileImageLoader.

Use Data Virtualization

When using ListBox, UI is virtualized, the data is not -- so although a 1,000 item list only has a fraction of the UI elements created, it needs all 1,000 of the data objects created and loaded, which can be a resource issue (long load times / high memory usage). This is because in desktop Silverlight the ListBox and other controls databind to IEnumerables, where the only option the control has is to enumerate the entire list to find out how large it is. Peter has a solution to this in his post on Data Virtualization.

Do not use ListBox**

If your application demands variable height items, but the number of items is managable enough to keep in memory. You should consider a solution without list box, example: David Anson talks about how to use StackPanel instead of a ListBox in his post on DefferedLoadListBox from Delay in order to get good performance from a scenario that's pretty common for social media applications: a scrolling list of entries with a picture and a brief bit of text. Its easy to try it out for your application.

Do not use Nested ListBox

If you have a need for nested list boxes, you should consider a solution similar to ListBoxGroupie

Other tips/approaches

  • HttpWebRequest must be used instead of WebClient. The reason for this is, there is a current platform issue where a request created via WebClient always returns on the UI thread, and again, we know that keeping the UI thread free is important.  Note: this is fixed in Mango, read about it here
  • When your list(in pivot/pano) is being populated, if you want to display a progress bar use the high performance progress bar
  • Sometimes you bind the list to an observable collection. In that case, Add items to the UI thread in batches every some miliseconds (example add 2 items every 20ms). This keeps the UI thread free for input from the user, avoiding stutters and delays, giving the perception of performance. This is much better than adding all 20 items in one go, drawing 20 items straight on the UI thread will keep it busy and wont take in the input from user, example the flick gesture for scroll. BingImageSearch is an example of one such application.
  • Peter has a good design example, where he stops loading the items if the list is scrolling. He elaborates about it in his blog on LazyListBox

Finally, we are incorporating all the feedback into the platform and your comments/feedback/questions are appreciated.

Thanks

Silverlight Windows Phone 7 Perfomance Team

Comments

  • Anonymous
    October 07, 2010
    Why shouldn't you use a usercontrol in a data template?

  • Anonymous
    October 07, 2010
    Good question Robbie, in short, "UserControls with XAML don’t cache their XAML so it’ll be read as a resource from the assembly on each instantiation." Heres more details on it: Control Templates are cached to the extent that their XAML is saved as a string by the ControlTemplate. It is parsed and instantiated at layout time. UserControls that have accompanying XAML do not cache their XAML, but this will be read as a resource from the assembly, and parsed. This happens when the UserControl is created. So the difference here is that with a Control, you bypass the need to load a resource stream to get the XAML each time. With a Control, there is an initial hit to load and parse generic.xaml, but that happens only once. WHen the built-in style is applied, the Template property will be set. For each instantiation: Control    Read/parse Generic.xaml (one time per assembly). ControlTemplates are saved as strings    Look up built-in style in ResourceDictionary    Apply built-in style    (Measure pass) ControlTemplate's XAML is parsed UserControl    (in ctor) InitializeComponent is called, XAML loaded as resource, and parsed Hence, the usercontrol takes a perf hit.

  • Anonymous
    October 07, 2010
    Could you elaborate on the use of HTTPWebRequest over WebClient? I've used WebClient extensively and didn't see any perf problems on a device, can I continue to use it? Are things likely to break when you fix the issue? Thanks

  • Anonymous
    October 08, 2010
    Will, Thank you for clarifying your concerns. Changes we make to WebClient will not break backward compatibility on applications already using it. Only reason we recommend HttpWebRequest over WebClient is the response to WebClient request comes on UI thread even though it was created on background thread. And if you have an image being downloaded on the UI thread, it will block the responsiveness of your application. However, if you are noticing that your activity on the UI thread isn’t impacting the performance, then great ! You already have a good performing app.

  • Anonymous
    October 08, 2010
    Thanks for the clarification :)

  • Anonymous
    October 11, 2010
    WHy avoid/remove custom controls from the data template ? Thanks

  • Anonymous
    October 11, 2010
    WHy avoid/remove custom controls from the data template ? Thanks

  • Anonymous
    October 20, 2010
    The comment has been removed

  • Anonymous
    November 01, 2010
    I have a question: are (some of) these principles applicable also to other Silverlight 4 WP7 containers such as StackPanel, WrapPanel or ScrollViewer ?

  • Anonymous
    April 18, 2011
    @Gabriel Listbox uses VirtualizingStackPanel, so many of these principles apply to VSP, which recycles the item-containers. If you look at the other blogpost recommended in this one, they are ListBoxVariant solutions using StackPanel. Simple things like loading images on background thread apply to all containers. @Gergely Orosz There are a lot of factors impacting the listbox performance. Its difficult to have a generic solution that caters to everyones scenario and maintains compatibility with Silverlight for Desktop. Given this, we have definitely taken into account all the feedback(criticism) and looked deeper into solving the problem from platform's prospective. Please refer to the MIX11 videos talking about SLM performance improvements focusing specifically on ListBox. Also, SLMPerf will have more blogposts on these new improvements soon. Again, thank you for the feedback.

  • Anonymous
    June 02, 2011
    Please refer to the post on Mango Improvements for listbox blogs.msdn.com/.../listbox-scrollviewer-performance-improvement-for-mango-and-how-it-impacts-your-existing-application.aspx

  • Anonymous
    June 27, 2011
    The comment has been removed

  • Anonymous
    September 27, 2011
    I have listbox binded content (observable collection, which have images too) On async request i populate collection by clearing and adding new content, at that time flicker occurs and seems it involved whole pivot page, on which i have listbox.

  • Anonymous
    July 02, 2012
    Any possibility to use vitrualization trough IList when I use observable collection for my ListBox? Or just use the batch approach mentioned above (adding 2 items every 20 ms to the UI thread)

  • Anonymous
    November 05, 2012
    David Anson's DeferredLoadListBox does not work for variable height items. Needs correction.

  • Anonymous
    November 12, 2012
    I know that the Windows Phone 7 ListBox use VirtualizingStackPanel by default to optimize memory. However, when I add more items to the view model, the listbox doesnot show those new items. I must scroll up, then down to see them. My view model does implement IList Many articles around have this problem How to fix this ?

  • Anonymous
    December 07, 2012
    "Add items to the UI thread in batches every some miliseconds (example add 2 items every 20ms)". Does switching between thread many times like this affect performance ?