How to create an infinite scrollable list with LongListSelector

How to create an infinite scrollable list with LongListSelector

  • Comments 10
  • Likes

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.

imageimage

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 events

LongListSelector has the following two events that can be used to detect when the user is approaching the end of data loading in memory.

image

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.

image

Initializing LongListSelector

The following shows how to reference the Windows Phone Toolkit controls in your XAML.

image

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.

image

Displaying progress

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.

image

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.

image

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.

Conclusion

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.

10 Comments
You must be logged in to comment. Sign in or Join Now
  • sanni
    0 Posts

    I want the grouping in the longlist selector with continuous loading data as like twitter api but with group header with it

    Is it possible?

  • animaX
    0 Posts

    Hi, thanks for the

    precious hints.

    In my app I have to download a lot of data in LongListSelector and

    I choise to put a button in the app bar to retrieve the data a bit a time.

    But also if I have a bit of data when the image in the item is loaded from the isolated storage of the app

    the refreh of the images is very slow.

    I saved the path of the image in one filed in the collection.

    The type of the collection is a my class which use the interfaces INotifyPropertyChanged, INotifyPropertyChanging so in this way the binding is automatic.

    Any suggestion is appreciated.

    Thanks a lot.

  • Great post for describing the LongListSelector - it's just what I needed.

    My next question isn't in any way designed to criticise, I'm just genuinely interested in best practice, and in getting my head round the MVVM pattern. My limited, noob understanding is that the Model is used as a means of keeping your app data in a format that is logical to the overall application (not just one page). The model will often reflect the database design (which this simplified app doesn't have). This model  is then reshaped into a form more suited to the UI of a specific page, with the addition of attributes and properties that make for easy DataBinding.

    With this in mind, does this app really have a model? It seems to me that the TwitterSearchResult class is simply part of the ViewModel? Am I being to pedantic? Have I misinterpreted the MVVM pattern? I'd really appreciate your comments.

  • - Pull-to-refresh is not the right design pattern for Windows Phone. As of today we do not recommend implementing such a pattern in Windows Phone app. Use a refresh button in the app bar or implement infinite scrolling.

    If you still want to implement such a pattern and would like to discuss the unsupported hacks to make it work, please post it on the developer forum(social.msdn.microsoft.com/.../threads) and paste a link here. I will try to address it there. Thanks!

  • sorry it happened again,  on mouse move if the vpc.viewport.top is 0 and point.y > first point.y then it is stretch on the top. if vpc.viewport.bottom = vpc.bounds.height and point.y

  • Sorry, some lines are missing in the code I pasted on the previous comment.

    void longListSelector_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)

    {

       move = false;

       Debug.WriteLine("Released");

    }

    void longListSelector_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)

    {

       Point p = e.GetPosition(longListSelector);

       if (move)

       {

    ViewportControl v = FindElementRecursive(longListSelector, typeof(ViewportControl)) as ViewportControl;

    if (v.Viewport.Top == 0)

    {

       if (startY = v.Bounds.Height)

    {

       if (startY > p.Y)

       {

    Debug.WriteLine("stretching bottom");

       }

    }

       }

       else

       {

    move = true;

    startY = p.Y;

       }

    }

  • Hi Rohan,

    Thanks for the information about infinite scrolling using ItemRealized in WP8 LongListSelector. Is there a way to find out the LongListSelector is stretched in WP8 so that I can pull down new data over network only when the user pulls down the list even after reaching the end of the list? I see that in wp7 we can use the VerticalCompression visual state of the ScrollViewer but in WP8 LongListSelector uses ViewportControl instead of the ScrollViewer.

    I hooked up to the MouseMove and MouseLeave event of the LongListSelector to detect the stretching of the list but it has some flaws, so I would like to know if there is another better way to do this.

           void longListSelector_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)

           {

               move = false;

               Debug.WriteLine("Released");

           }

           void longListSelector_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)

           {

               Point p = e.GetPosition(longListSelector);

               if (move)

               {

                   ViewportControl v = FindElementRecursive(longListSelector, typeof(ViewportControl)) as ViewportControl;

                   if (v.Viewport.Top == 0)

                   {

                       if (startY = v.Bounds.Height)

                   {

                       if (startY > p.Y)

                       {

                           Debug.WriteLine("stretching bottom");

                       }

                   }

               }

               else

               {

                   move = true;

                   startY = p.Y;

               }

           }

    Thanks,

    Pradeep

  • @Monstroplante - They are now called ItemRealized and ItemUnrealized events in WP8 SDK.

  • I can't find Link and Unlink events on the Windows Phone 8 SDK. Did I miss something ?

  • Dear Sir,

    Great post! I know that this is not the right place for this question and I'm sorry to bother you but I couldn't find a better place! So I just ask:

    How can I get you to post about my newly developed library on codepldex http://slasync.codeplex.com in windows phone development blog?

    It greatly facilitates asynchronous calls in windows phone and Silverlight using the Microsoft's Async CTP. As you might know the async and await keywords are great but not all classes are supported by them, my code makes it possible for all async calls to be made using this method.

    Best Regards