This blog post was authored by Rohan Thakkar, a Program Manager on the Windows Phone team.
Last year we evangelized the use of the LongListSelector control to provide smooth infinite scrolling scenarios. The LongListSelector control is so useful that we decided to enhance it and move it to the SDK for Windows Phone 8. In this post we discuss the improvements we’ve made to the control, and provide a mapping guide for Windows Phone developers who are already using the Windows Phone Toolkit 7.1 version of the LongListSelector.
If you prefer to read XAML instead of plain text, you can go straight to the samples and explore them:
For more info about how to use the LongListSelector, see How to display data in a grouped list in LongListSelector for Windows Phone 8.
Let’s dig a little deeper into various enhancements we’ve made to the control. The following sections are provided in this post.
The LongListSelector control is now a part of Microsoft.Phone.Controls namespace in Microsoft.Phone.Controls.dllassembly. This means it’s now a fully supported, high-quality control shipped by the Windows Phone Development team. We also moved the assembly to ROM to take advantage of the internal off-thread input and the render thread architecture. This means the control is optimized for the full potential of Windows Phone.
The Microsoft.Phone.Controls.dll assembly also contains other phone-specific controls, such as Panorama and Pivot. These controls also get the performance benefits of being in ROM, including reduced memory consumption (~50% reduced memory for a basic app) and improved touch performance, especially when you have data being loaded in the panorama view.
The native Windows Phone grouped list has the headers stick to the top as you scroll. The LongListSelector control in Windows Phone 8 has the same smooth effect.
Note the headers in the following screenshots.
Figure 1 - Notice group header "a"
Figure 2 - Scrolling up, notice how "a" sticks to top
Figure 3 - Notice how the group header "b" pushes "a"
Figure 4 - Now "b" is sticky, same as "a"
In Windows Phone 8, LongListSelector supports grid layout, which is more than just the WrapPanel that’s available in the Windows Phone Toolkit. The LongListSelector grid layout is virtualized, which provides better performance. The following screenshots are from the PhotoHubsample.
Figure 5 - LongListSelector's Grid layout
Figure 6 - Jumplist's List layout.
The following code is an excerpt of the XAML for the LongListSelector from the PhotoHub sample.
Let’s look at some examples of interesting properties found in this code.
LayoutMode – Indicates whether the collection in the context should be displayed as a list or as a grid. In the preceding XAML example, LayoutMode is set to Grid as a property on the LongListSelector, and set to List as a property on JumpListStyle.
JumpListStyle– Provides the style for the jump list items.
GridCellSize – Indicates the size of each cell in the grid. This property has to be set on the LongListSelector or the JumpListStylewherever the grid layout is to be rendered.
Converters - Note that the JumpListItemBackgroundConverter and JumpListItemForegroundConverterare needed to convert the foreground and background colors of the jump list item (group header of a group) whether or not it has items in the group. These converters also are part of the SDK and are in the same Microsoft.Phone.Controls namespace.
Figure 7 - Value converters shading empty group jump list items
The default foreground and background colors match the first-party app. You can customize it to align with your design needs using the Enabled and Disabled properties as shown here:
Earlier we spoke about infinite scrolling for the Windows Phone Toolkit 7.1 LongListSelector. As you approach the end of the visible list when scrolling, the LongListSelector automatically fetches more items and adds them to the list, which gives you a sense of infinite scrolling. We made this scenario simple to implement in Windows Phone 8. The following code from the Twitter Search sampledemonstrates how easy it is to implement:
The ItemRealized event is raised every time a LongListSelector item acquires a UI container to be displayed on the screen. In other words, every time an item enters the UI buffers above or below the current viewport, the ItemRealized event is raised. The event argument property ItemKind indicates whether the UI container is an Item, ListHeader, GroupHeader, or ListFooter. Using the property Container.Contentyou can get the actual object associated with the UI container that was realized. This way you can monitor the objects within the UI container buffer.
Note how the app code in this example contains a private variable _offsetKnob. This helps fine-tune the LongListSelector scrolling experience by helping to determine when to load more items depending on how heavy your item template is, or on how slow the response is from the service sending the data.
When you group contacts in alphabetical order, you want to do this in all languages. You could provide your own globalized, sorted alphabet characters for group headers. However, using your own alphabet strings will not guarantee 100% matching with the phone first-party contacts list. So we introduced a class called SortedLocaleGrouping that provides a set of alphabets that are the same as those used by the first party. In the PeopleHub sample, SortedLocaleGrouping (from Microsoft.Phone.Globalization namespace) is used in one of the helper types, AlphaKeyGroup(which also is very highly recommended).
You get the group display names by using the SortedLocaleGrouping.GetGroupDisplayNames property to populate your groups. Then use the GetGroupIndexmethod to classify your contacts list.
This is a unique property and we have included it in SortedLocaleGrouping. In some cultures, such as ja-JP, last names are written in a different script and are pronounced differently depending on the region or background.
Here’s an example:
String of LastName
Group based on Yomi
Group without Yomi
新井 (display string)
Nii --> にいい (in Hiragana) or ニイイ (in Katakana)
The Globe icon
Arai --> あらい (in Hiragana) or アライ (in Katakana)
Shinkyo --> しんきょ (in Hiragana) or シンキョ (in Katakana)
This is a common phenomenon catching on in different cultures, and the first-party contacts list will be grouped based on the Yomi that is passed in. If no Yomi is passed in, it will return the default, same group (equivalent to other or globe).
You usually would use the SupportsPhonetics property when classifying the contacts into groups and if you have the Yomi (pronunciation) database that you can access via a service or other means for the specific culture. The code between the //EXAMPLE comments in the following example is from one of the helper methods that shows how you would use it if you have a database of the pronunciations (Yomi) for various names.
We modified and enhanced the Windows Phone Toolkit LongListSelector. In this section we briefly outline what has changed.
Windows Phone Toolkit 7.1
Windows Phone 8 ROM SDK
Display all groups in the list whether or not they have items. Default is true.
Hide all groups in the list without items. Default is false.
Gets or sets whether the list is flat instead of a group hierarchy. Default is true.
Gets or sets whether the list is flat instead of a group hierarchy. Default is false.
(coupled with ManipulationState property)
With EventArgs including ItemKind
You have to know how many elements there are and there is no Count property on IEnumerable. You also have to be able to access the items by index, not just in the forward-only, one-at-a-time way that enumerators do. If ItemsSource accepted IEnumerables or an IEnumerable of IEnumerables, you’d have to convert them to lists internally using the default method of iterating over every single item. This conversion would rule out data virtualization, which could cause poor performance without the app author knowing why. Worse yet, the author might think that it is the status quo and simply accept a longer start time. This was one of the complaints about the original toolkit LongListSelector. Now, if an app author has only an IEnumerable set of data, the developer can simply call ToList() for the default conversion to an IList but the developer also has the flexibility provide their own IListimplementation.
Yes! We have designed the LongListSelector specifically for phone scenarios and we encourage people to use the LongListSelector instead of ListBox for phone apps.
LongListSelector does not support touchable objects like buttons in its items - all touches are translated into item selection. The other day, I was refactoring from LongListSelector back to ListBox.
What would have helped tremendously to make the transition from ListBox more attractive for people is a bindable SelectedItem property. That is a real annoyance and I hope it will be fixed soon.
Other than that it's a great control and a great move to integrate it more deeply into the platform. Thanks!
The improvements to the LongListSelector control in WP8 are very welcome. SortedLocaleGrouping is great!
I've come across a couple of annoyances:
1. Scrollbars in both the main LongListSelector display and jump list popup take up horizontal space, adding a margin on the right of the content. The margin disappears if the content isn't tall enough to mean scrolling is necessary. This didn't happen with the WP7 Toolkit LongListSelector.
2. Adding items to the collection that is the ItemsSource of the LongListSelector control seems to scroll the list to the bottom. I had to add a call to ScrollTo to work around this. Again, this wasn't an issue in the WP7 Toolkit control. (For reference, my collection is of the type ObservableCollection>).
One other thing: it'd be nice if we could use 'Stretch' as the HorizontalAlignment for the top-level control in the DataTemplate for JumpListStyle, rather than setting the width manually (it's set to 470 in the example in this post).