Jumplists in Windows Phone 8.1 (Updated)

You’re writing a WP8.1 XAML app and you’re looking for some kind of jumplist control. Well, you won’t find one and the LongListSelector is nonexistent unless you go back to using Silverlight. So read on if you want to create a proper jumplist experience with the proper Windows Phone UX.

Update: The contents of this post have been updated in Part 2 called “Making WP8.1 JumpLists Better” and most if not all of the resources have changed. This post will not be updated for historical purposes but the Sample Solution and Resources will reflect the most up to date implementation of the JumpList.

IMPORTANT: While these posts about JumpLists are super informative, I highly recommend checking out my JumpList controls in my QKit library and download them from nuget. QKit includes ready-to-use controls like the AlphaJumpList control so you don’t have to deal with the headaches of implementing it from scratch along with several other useful controls. You can also view the source code on http://qkit.codeplex.com/.

The Material

VS_IconSAMPLE SOLUTION – see it in action
Code_IconRESOURCES – styles, templates, and code to copy+paste
News_IconPART 1 – Jumplists in Windows Phone 8.1 (You are here)
News_IconPART 2 – Making WP8.1 JumpLists Better

The Problem

Windows Phone has a unique way to group and traverse through a list very quickly. In Silverlight apps, we were given a dedicated control called the LongListSelector that enabled third party apps to simulate that experience. With the new Universal app model and WP8.1 XAML running on WinRT, that control is not available. That’s the first problem. The second problem is even if we can create the jumplist experience, it might not to look and feel like the native jumplists that are in the people hub and the app list since there are no XAML resources, styles, or samples for this. This means that developers will have to come up with their own solution. Some will have pixel-perfect recreations of the jumplist while others will be happy with a “close enough” solution.

The Solution

First, let’s prepare our data. The data needs to be grouped properly and I’ve written a “JumpListHelper” helper class that you can drop in and reuse for all of your jumplist needs. It groups and sorts the list into a list of JumpListGroup objects using two extension methods. To group the items into alphabetical groups like you’d find in the app list, you simple add a using statement to my helper class and then call:

var groups = items.ToAlphaGroups(x => x.Name);

…where “items” is a list of objects you want to display in your list. The ToAlphaGroups method takes a function that gets the value of the object you want to group and sort on. In this case, my items have a property called “Name” and using a lambda function, I’m selecting that property. Use this extension method if you want the following experience:

AlphaGrouping

To group it into a more generic group, my helper class also has a ToGroups method.

var groups = items.ToGroups(x => x.Name, x => x.Category);

This method takes two functions as parameters to define its sort and grouping values separately. In this case, I still want the items to be sorted by name, but I want the items to be grouped by the “Category” property. This is generally used to get a more general grouping of lists and this kind of jumplist can be found in the photos app.

GenericGrouping

Once the data is grouped, we will be using a CollectionViewSource class to expose it to the jumplist via binding. Just create a property in your viewmodel and instantiate it like this:

private CollectionViewSource collection;
public CollectionViewSource Collection
{
    get
    {
        if (collection == null)
        {
            collection = new CollectionViewSource();
            collection.Source = groups; //groups is the result of using my extension methods above
            collection.IsSourceGrouped = true;
        }
        return collection;
    }
}

Now, we’ll actually build the UI for the jumplist. The jumplist is created using a combination of 3 controls:

  • ListView – the ListView is the go-to list control in WinRT to display your items. It’s virtualized, enables animations, and maintains the current view.
  • GridView or 2nd ListView – a GridView will be used when displaying all of the letters your list can jump to (for alpha-jumplists) while another ListView is used to display all categories/groups (generic jumplists).
  • SemanticZoom – this controls acts as switch between the two previous controls. When in the normal ListView control, tapping on the letter or group header will automatically bring up the second ListView/GridView.

To set up the jumplist, we combine the controls like so:

<SemanticZoom Style="{StaticResource AlphaJumpListStyle}">
    <SemanticZoom.ZoomedInView>
        <ListView ItemsSource="{Binding Collection.View}">
            <ListView.GroupStyle>
                <GroupStyle HeaderTemplate="{StaticResource AlphaGroupHeaderTemplate}"
                            HeaderContainerStyle="{StaticResource JumpListListHeaderContainerStyle}"
                            HidesIfEmpty="True" />
            </ListView.GroupStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    ...
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <GridView ItemsSource="{Binding Collection.View.CollectionGroups}"
                  ItemTemplate="{StaticResource AlphaJumpListItemTemplate}" />
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

Note: All of the styles and templates will be available in the sample project at the beginning of this post.

Let’s break down what’s going on. The SemanticZoon control has a style applied to it and it is required for it to look like a proper jumplist. The style is also different between the alpha jumplist and the generic jumplist so be sure to apply the right one. The reason for this is because the alpha jumplist uses a Viewbox control to keep the UX consistent with the OS. The letters grid when the alpha jumplist is open is one of the few areas in the OS that doesn’t change between different screen resolutions and sizes. WP8 will scale elements on the screen differently for different screens. But with the letters grid, it’s stretched to fill the screen as if it’s an image. To accomplish this in our jumplists, we need to use the Viewbox control. You can see the difference it makes below (Viewbox used on the left) on a 1080p 5.5in device.

Viewbox WithoutViewbox

Note that only the alpha jumplist exhibits this behavior so it’s the only one to use the Viewbox in its style. The generic jumplist doesn’t use it.

Now digging deeper, we can see that the SemanticZoom control has a zoomed in and zoomed out component. The zoomed in view is the main ListView that the user will be first presented with. This zoomed in ListView’s ItemsSource is bound to the CollectionViewSource that we created. It also has a GroupStyle that defines how the headers will look. The GroupStyle defines a template for the header but also has a container style that fixes a bug where the first header will disappears when you navigate away from the page. Make sure to include this container style (thanks to Kinnara on the MSDN forums for solving this issue).

The zoomed out view is shown when the user taps on a group header. It is a GridView for an alpha jumplist and a ListView for a generic jumplist. Its ItemsSource is bound to the CollectionViewSource but to the View’s CollectionGroups collection. Make sure to check out the sample project to define the XAML properly and all of the styles and templates. Omitting anything runs the risk of the jumplist not working properly, reintroducing a bug, or making it look incorrect.

Remarks

This currently doesn’t work in landscape. Because alpha jumplist’s GridView doesn’t scale against the screen resolution, a Viewbox control was used in the SemanticZoom zoomed out view. Unfortunately, using a Viewbox means that I had to hard code the size and currently doesn’t resize when the phone rotates. So don’t enable landscape orientation for pages that use alpha jumplists. The generic jumplist works fine with page rotation, however.

There is also a performance issue when there’s a CommandBar on the page. The SemanticZoom control automatically hides the CommandBar when the user taps on the group header but it’s somewhat slow on a real device. I suggest hooking up to the SemanticZoom.ViewChangeStarted event and hiding the CommandBar manually like so:

private void SemanticZoom_ViewChangeStarted(object sender, SemanticZoomViewChangedEventArgs e)
{
    if (e.IsSourceZoomedInView)
        this.BottomAppBar.Visibility = Visibility.Collapsed;
    else
        this.BottomAppBar.Visibility = Visibility.Visible;
}

Finally, these styles do not currently support the high contrast mode that Windows Phone can be in. In some cases, text is unreadable in high contrast mode and at the very least, it doesn’t match the system UI in high contrast mode. I’ll probably be revisiting this at a later time to get the high contrast mode working properly but right now it’s not a priority.

Advertisements

12 thoughts on “Jumplists in Windows Phone 8.1 (Updated)

    1. Just updated the sample with a new and improved JumpListHelper class. It now uses the CharacterGroupings class and because of that, it now matches international JumpLists. Feel free to check it out if you want.

  1. Hello, I try to implement this to my project
    I have a json data for my listview

    I have some problem with async Task
    in this part:
    data = items.ToGroups(x => x.Title, x => x.Category);

    i got squigly red line :

    <Task<List> does not contain a definition for ToGroups and no extension method “ToGroups” accepting ….

    do you have any reference?
    thanks.

    1. The ToGroups and ToAlphaGroups are extension methods that are a part of my JumpListHelper class. You need to include a copy of that class found in the sample solution in your solution and include the using statement to that class at the top where you’re using this method. Another way to use the extension methods is by using it like:
      data = JumpListHelper.ToGroups(items, x => x.Title, x=> x.Category);

      This is more friendly with Visual Studio’s intellisense and will help add the correct using statement for you.

      But the JumpListHelper class in the sample solution is out of date. If you want to easily add JumpList controls and have the up to date grouping operations, you should install and use the QKit nuget package. http://qkit.codeplex.com/. It’s easier to create the JumpList ui in xaml since you don’t have to manually define the SemanticZoom and styles and you also don’t have to worry about CollectionViewSource. Just use the JumpListHelper class to group the data and feed it to the included JumpListControls. More info on how to use QKit’s JumpList controls can be found here and here.

  2. Hello this looks really good, but I wasnt able to figure out, how to manipulate with these items. How can I delete, edit, or add items into this MovieList? I would like to have for users opurity to administrate items that he see in this MovieList.
    I will be really grateful for reply, Grow#.

    1. Sorry for the late reply. Currently this only supports static lists and changes to a collection needs to be rebuilt. I’ll have to go back and look into implementing this eventually using ObservableCollection when I find some free time. For now, one workaround I’ve used is have a “view mode” and “edit mode.” In the viewing mode, present the list as grouped but during edit mode, just a normal flat list bound to ObservableCollection. Once the user is done modifying the ObservableCollection, rebuild the grouped list and switch to that view. Not elegant I know.

  3. Hi,

    Your implementation looks very nice.
    I wanted to use it however I have defined my models in a portable Library instead of the main project. The nuget package seem not to be able to install itself on this project (as it is not UI project), and therefore I can’t use the Jumplistgroup/Jumplisthelper from there.
    Is there any way besides loading all classes from codeplex?

    Thanks 🙂

    1. Hi sorry for the late reply but as of right now, I don’t think so. I know this is not ideal but I originally designed this specifically for phones. Nothing is stopping you from just copying pasting the source code into your own projects for now though. I will be working to making this work across pc and phones if I can find time but I may end up only doing that through convenience when updating this for Windows 10. Sorry that I don’t have a better answer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s