Virtualizing Data in Windows Phone 7 Silverlight Applications

One of the cool features of lists in Silverlight is that they can "virtualize" the UI objects needed to render the list, reducing the amount of memory and CPU necessary to load large lists. For example, if you bind a ListBox to 1,000 items in Silverlight, it will only create ListBoxItems for the first few screens' worth of data (say, 30 objects) and create the UI for those based on the DataTemplate. The other 970 items do not get UI objects generated for them, which is a great saving of resources. As you scroll through the list, Silverlight recycles these container items and binds them against the rest of the data, giving the illusion that all the items are in the list at once.

One of the limitations of this in desktop Silverlight is that although the UI is virtualized, the data is not -- so although that 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.

Enter Silverlight for Windows Phone, where we are more resource constrained than the desktop and can't afford to create all those data items like the desktop can. A simple solution is available for this, called data virtualization. The trigger for this is using an object that implementes IList (instead of just IEnumerable) as your ItemsSource. Using this more flexible interface, Silverlight can simply query the list's Count to find out how large it is and can request the individual items it needs to fill the virtualized UI objects via the indexer. This approach enables databounds lists in Windows Phone 7 to be essentially unlimited in size; the sample attached to this post is a list of 1,000,000 objects (yes, <Dr. Evil voice> one million objects! </Dr. Evil voice> ) that binds incredibly quickly, jumps to any point incredibly quickly, and scrolls like a champ. Try doing that on the desktop!

The sample also shows using a (very, very dumb) cache for storing even more objects than Silverlight virtualizes, in case you want to speed up certain operations. In this example, the cache is a dumb MRU cache that really only works for scrolling back through the list (if you scroll from 0 - 50 and then scroll back down to 0, a lot of the items will be returned as "cached items"). I don't recommend you actually use this cache, because it is dumb and slow, but you can see how the technique could be used to provide smart caching, or even predictive pre-loading of items, etc. to best balance memory usage and performance.

The only IList members you need to implement are:

  • Count, to return the actual number of items in your list;
  • IndexOf, to return the index of a specified item if it is in the list; and
  • this[] , to return the item at a given location (implementing set is not required)

Everything else can simply throw NotImplementedException, although of course it is nice to implement the other members if you play to use your data list in any context other than databinding.

VirtualizingDataTest.zip