Windows Phone users love to swipe their phones smoothly to get to the information they want. Whether it’s swiping horizontally via panorama and pivot controls, or swiping vertical lists in areas such as the People Hub, users view the phone as a small window into an infinite amount of useful information.
We as developers have a responsibility to make it look and feel like the information is always available in the viewport while users are swiping around. To maintain this perception of infinite scrolling, we would like to have all the data loaded in memory. However, for most practical scenarios, we cannot possibly have all the data pre-loaded. The News feed in the People Hub is a classic example of fetching fresh data from a web service.
In this post, I describe how to pre-fetch information to create an infinite scrollable list for Windows Phone 7.5 using the LongListSelector control. This approach is sometimes called the “Loading…pattern.” This post assumes that you know how to bind and load data into a ListBox.
An infinite list sample
To demonstrate how to create an infinite scrollable list, we (the Windows Phone developer platform team, of which I’m a member) created a simple code sample. Click here to download the .zip file.
The sample is designed to load Twitter search results on the fly until there are none more to load, giving the user a sense of infinite scrolling. This sample uses the LongListSelector control (included in the sample). To download and install LongListSelector and other Toolkit controls separately, go to the Windows Phone Toolkit site.
LongListSelector vs. ListBox
In the past, we evangelized that you should use ListBox and its compression states to detect when you have reached the bottom of a list to load more items. While this was a good pattern, we iterated more with the UX team and realized that users should not even have to compress to get more data. Users should just scroll and items should be added without him having to pause/wait for items. As the user approaches the last of the currently loaded items in memory, we should load more items early enough that the user never sees compression at the end of the list.
Unfortunately, ListBox does not provide any direct mechanism to detect when the user is approaching the end of list. There are some unsupported ways in which you can hack around to detect where the scroll bar is on the list and load more items. This is definitely not a recommended approach. We cannot promise backward-compatibility for such hacks if they hinder performance optimizations on the platform.
You can choose to implement a list using your own custom controls, but we recommend using the LongListSelector control in the Windows Phone Toolkit.
LongListSelector has the following two events that can be used to detect when the user is approaching the end of data loading in memory.
The Link event is raised every time a list item in memory is assigned a UI container. In other words, Link is raised every time new data appears in the viewport (and its buffers). Similarly, the Unlink event is raised every time an existing data item with an assigned UI container is un-assigned (no longer has a UI container). In other words, Unlink is raised when a data item is scrolled off from the viewport (and its buffers).
These events give developers a much better way to determine what data is on screen and what is not. Using this information you can trigger loading of more items as the user approaches the end of a list.
Let’s explore certain parts of the code sample.
Loading the data
In the sample, we use a simple Model/ViewModel approach to load data. You will have similar bindings to your corresponding ViewModels.
TwitterViewModel has the following public properties/methods.
The following shows how to reference the Windows Phone Toolkit controls in your XAML.
Among other controls on the page, you will include the LongListSelector control. The following shows how to initialize the LongListSelector. Notice the IsFlatList property is set to True. Items do not get rendered if you don’t set this property for flat lists.
In the code-behind, there are three important observations.
First, we use the SystemTray’s Progress indicator and bind it to the IsLoading property of our viewmodel in the MainPage.Loaded’s event handler. In the above screenshot, you can see the SystemTray’s ProgressIndicator is used to display progress. This is the recommended way to display progress.
Handling the LongListSelector.Link event
Second, and the heart of this post, is by using the LongListSelector.Link event we detect what item is being linked (appears in the UI buffer) and whether it has a certain offset (5th in this example) from the last item of the data loaded in memory. If the item appears in the UI buffer at a certain offset, we fetch more items. We want to keep the application responsive while fetching more items so we make the requests for more data on a background thread. To keep track of the pages, we use a pageNumber value.
Adjusting the offset
Finally, you can tweak the offsetKnob value depending on how many items you are fetching from the server, how slow the server is, or how heavy the items are. The idea is that this knob will vary for each app depending on various factors. Keep in mind that the end-user should always get a sense of infinite scrolling.
To make this code work, you will need to hook up all the appropriate events, parse the feed you receive from the Twitter API, call the first LoadPage, and so on. We hope to see tons of apps with beautifully loading long lists and we continue to work towards making infinite scrolling and other list scenarios easier to implement for developers.
Thanks for reading and let us know what you think.
Updated November 7, 2014 11:56 pm