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