Windows Phone 8.1 XAML Jumplist

Here are the styles, templates, and XAML for quick copy and pasting. View this blog post about WP8.1 jumplists for more information and this blog post about improvements made on it.

Styles+Templates

The styles and templates needed for both Alpha and Generic Jumplists are contained in a XAML file called JumpList.xaml. Include the file in your project and reference it in your App.xaml like so:

<Application x:Class="JumpListSample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="using:JumpListSample">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Assets/Styles/JumpList.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

If you do not have the JumpList.xaml file, you can get it from the sample project here or create your own using the source code below:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.ThemeDictionaries>
        <ResourceDictionary x:Key="Default">
            <JumpListItemBackgroundConverter x:Key="JumpListItemBackgroundConverter" />
            <JumpListItemForegroundConverter x:Key="JumpListItemForegroundConverter" />
            <Thickness x:Key="JumpListItemBorderThickness">0</Thickness>
            <Thickness x:Key="JumpListItemTextMargin">9.5,0,0,9.5</Thickness>
            <Thickness x:Key="AlphaJumpListGroupTextMargin">5.5,0,0,9.5</Thickness>
            <SolidColorBrush x:Key="JumpListItemBackgroundBrush"
                             Color="{ThemeResource SystemColorControlAccentColor}" />
            <SolidColorBrush x:Key="JumpListItemTextForegroundBrush"
                             Color="White" />
        </ResourceDictionary>
        <ResourceDictionary x:Key="HighContrast">
            <JumpListItemBackgroundConverter x:Key="JumpListItemBackgroundConverter" />
            <JumpListItemForegroundConverter x:Key="JumpListItemForegroundConverter" />
            <Thickness x:Key="JumpListItemBorderThickness">2.5</Thickness>
            <Thickness x:Key="JumpListItemTextMargin">7,0,0,7</Thickness>
            <Thickness x:Key="AlphaJumpListGroupTextMargin">5.5,0,0,7</Thickness>
            <SolidColorBrush x:Key="JumpListItemBackgroundBrush"
                             Color="Transparent" />
            <SolidColorBrush x:Key="JumpListItemTextForegroundBrush"
                             Color="{ThemeResource SystemColorControlAccentColor}" />
        </ResourceDictionary>
    </ResourceDictionary.ThemeDictionaries>
    <!--DATA TEMPLATES-->
    <!--Item templates for ZoomedOutView GridView/ListView-->
    <DataTemplate x:Key="AlphaJumpListPickerItemTemplate">
        <Border Background="{Binding Converter={StaticResource JumpListItemBackgroundConverter}}"
                BorderBrush="{Binding Converter={StaticResource JumpListItemForegroundConverter}}"
                BorderThickness="{ThemeResource JumpListItemBorderThickness}"
                Height="79"
                Width="79"
                HorizontalAlignment="Left"
                Margin="0,0,9.5,9.5">
            <TextBlock Text="{Binding Group.Key}"
                       Foreground="{Binding Converter={StaticResource JumpListItemForegroundConverter}}"
                       FontSize="38.667"
                       FontWeight="SemiBold"
                       TextLineBounds="Tight"
                       OpticalMarginAlignment="TrimSideBearings"
                       IsColorFontEnabled="False"
                       IsTextScaleFactorEnabled="False"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Bottom"
                       Margin="{ThemeResource JumpListItemTextMargin}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="GenericJumpListPickerItemTemplate">
        <Border Background="{Binding Converter={StaticResource JumpListItemBackgroundConverter}}"
                BorderBrush="{Binding Converter={StaticResource JumpListItemForegroundConverter}}"
                BorderThickness="{ThemeResource JumpListItemBorderThickness}"
                Height="49.5"
                Margin="0,0,0,9.5"
                HorizontalAlignment="Stretch">
            <TextBlock Text="{Binding Group.Key}"
                       Foreground="{Binding Converter={StaticResource JumpListItemForegroundConverter}}"
                       FontSize="22"
                       FontWeight="SemiBold"
                       TextLineBounds="Tight"
                       OpticalMarginAlignment="TrimSideBearings"
                       IsColorFontEnabled="False"
                       IsTextScaleFactorEnabled="False"
                       VerticalAlignment="Bottom"
                       Margin="{ThemeResource JumpListItemTextMargin}" />
        </Border>
    </DataTemplate>
    
    <!--Sticky header templates-->
    <DataTemplate x:Key="AlphaGroupHeaderTemplate">
        <Border Background="{ThemeResource JumpListItemBackgroundBrush}"
                BorderBrush="{ThemeResource PhoneAccentBrush}"
                BorderThickness="{ThemeResource JumpListItemBorderThickness}"
                Width="49.5"
                Height="49.5"
                HorizontalAlignment="Left"
                Margin="0,0,0,9.5">
            <TextBlock Text="{Binding Key}"
                       Foreground="{ThemeResource JumpListItemTextForegroundBrush}"
                       FontSize="39"
                       FontFamily="{StaticResource PhoneFontFamilySemiLight}"
                       TextLineBounds="Tight"
                       OpticalMarginAlignment="TrimSideBearings"
                       IsColorFontEnabled="False"
                       IsTextScaleFactorEnabled="False"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Bottom"
                       Margin="{ThemeResource AlphaJumpListGroupTextMargin}" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="AlphaBorderGroupHeaderTemplate">
        <Border Background="Transparent"
                BorderBrush="{ThemeResource PhoneAccentBrush}"
                BorderThickness="2.5"
                Width="49.5"
                Height="49.5"
                HorizontalAlignment="Left"
                Margin="0,0,0,9.5">
            <TextBlock Text="{Binding Key}"
                       Foreground="{StaticResource PhoneAccentBrush}"
                       FontSize="33"
                       FontFamily="{StaticResource PhoneFontFamilySemiLight}"
                       TextLineBounds="Tight"
                       OpticalMarginAlignment="TrimSideBearings"
                       IsColorFontEnabled="False"
                       IsTextScaleFactorEnabled="False"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Bottom"
                       Margin="5.5,9,0,8.5" />
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="GenericGroupHeaderTemplate">
        <Border>
            <TextBlock Text="{Binding Key}"
                       Foreground="{ThemeResource PhoneAccentBrush}"
                       FontSize="24"
                       FontWeight="SemiLight"
                       OpticalMarginAlignment="TrimSideBearings"
                       IsTextScaleFactorEnabled="False"
                       VerticalAlignment="Bottom"
                       Margin="0,0,0,9.5" />
        </Border>
    </DataTemplate>

    <!--STYLES-->
    <!--Disappearing sticky header fix, apply to ZoomedInView group styles-->
    <Style x:Key="JumpListListHeaderContainerStyle"
           TargetType="ListViewHeaderItem">
        <Setter Property="HorizontalContentAlignment"
                Value="Stretch" />
        <Setter Property="VerticalContentAlignment"
                Value="Stretch" />
    </Style>

    <!--Styles of ZoomedOutView GridView/ListView-->
    <Style x:Key="AlphaJumpListPickerStyle"
           TargetType="GridView">
        <Setter Property="ItemTemplate"
                Value="{StaticResource AlphaJumpListPickerItemTemplate}" />
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="GridViewItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="GridViewItem">
                                <Border x:Name="TiltContainer">
                                    <VisualStateManager.VisualStateGroups>
                                        <VisualStateGroup x:Name="CommonStates">
                                            <VisualState x:Name="Normal" />
                                            <VisualState x:Name="Pressed">
                                                <Storyboard>
                                                    <PointerDownThemeAnimation Storyboard.TargetName="TiltContainer" />
                                                </Storyboard>
                                            </VisualState>
                                            <VisualStateGroup.Transitions>
                                                <VisualTransition From="Pressed"
                                                                  To="Normal">
                                                    <Storyboard>
                                                        <PointerUpThemeAnimation Storyboard.TargetName="TiltContainer" />
                                                    </Storyboard>
                                                </VisualTransition>
                                            </VisualStateGroup.Transitions>
                                        </VisualStateGroup>
                                    </VisualStateManager.VisualStateGroups>
                                    <ContentPresenter ContentTransitions="{TemplateBinding ContentTransitions}"
                                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                                      Content="{TemplateBinding Content}"
                                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                      Margin="{TemplateBinding Padding}" />
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="GenericJumpListPickerStyle"
           TargetType="ListView">
        <Setter Property="ItemTemplate"
                Value="{StaticResource GenericJumpListPickerItemTemplate}" />
        <Setter Property="HorizontalContentAlignment"
                Value="Stretch" />
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment"
                            Value="Stretch" />
                </Style>
            </Setter.Value>
        </Setter>
    </Style>

    <!--Styles of SemanticZoom-->
    <Style x:Key="AlphaJumpListStyle"
           TargetType="SemanticZoom">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="SemanticZoom">
                    <Grid>
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}">
                            <Grid Margin="{TemplateBinding Padding}">
                                <ContentPresenter x:Name="ZoomedInPresenter"
                                                  Content="{TemplateBinding ZoomedInView}"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                                <Popup x:Name="Popup">
                                    <Popup.ChildTransitions>
                                        <TransitionCollection>
                                            <PopupThemeTransition />
                                        </TransitionCollection>
                                    </Popup.ChildTransitions>
                                    <Grid>
                                        <Rectangle Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}"
                                                   Opacity=".67" />
                                        <Border x:Name="PopupBorder">
                                            <Viewbox Stretch="Uniform"
                                                     VerticalAlignment="Top">
                                                <ContentPresenter x:Name="ZoomedOutPresenter"
                                                                  Height="625"
                                                                  Width="364"
                                                                  Content="{TemplateBinding ZoomedOutView}"
                                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                                  Margin="19,15,0,-57.5" />
                                            </Viewbox>
                                        </Border>
                                    </Grid>
                                </Popup>
                            </Grid>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="GenericJumpListStyle"
           TargetType="SemanticZoom">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="SemanticZoom">
                    <Grid>
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}">
                            <Grid Margin="{TemplateBinding Padding}">
                                <ContentPresenter x:Name="ZoomedInPresenter"
                                                  Content="{TemplateBinding ZoomedInView}"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                                <Popup x:Name="Popup">
                                    <Popup.ChildTransitions>
                                        <TransitionCollection>
                                            <PopupThemeTransition />
                                        </TransitionCollection>
                                    </Popup.ChildTransitions>
                                    <Grid>
                                        <Rectangle Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}"
                                                   Opacity=".67" />
                                        <Border x:Name="PopupBorder">
                                            <ContentPresenter x:Name="ZoomedOutPresenter"
                                                              Content="{TemplateBinding ZoomedOutView}"
                                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                              Margin="19,15,19,0" />
                                        </Border>
                                    </Grid>
                                </Popup>
                            </Grid>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Defining the JumpList

Copy and paste this into your pages that need a jumplist.

To define an Alpha Jumplist in your page, copy and paste the following:

<SemanticZoom Style="{StaticResource AlphaJumpListStyle}"
              Margin="19,0,0,0">
    <SemanticZoom.ZoomedInView>
        <ListView ItemsSource="{Binding Collection.View}">
            <ListView.GroupStyle>
                <GroupStyle HeaderTemplate="{StaticResource AlphaGroupHeaderTemplate}"
                            HeaderContainerStyle="{StaticResource JumpListListHeaderContainerStyle}"
                            HidesIfEmpty="True" />
            </ListView.GroupStyle>
            <ListView.ItemTemplate>
                <!--Your item datatemplate here-->
            </ListView.ItemTemplate>
        </ListView>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <GridView ItemsSource="{Binding Collection.View.CollectionGroups}"
                  Style="{StaticResource AlphaJumpListPickerStyle}" />
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

To define an Generic Jumplist in your page, copy and paste the following:

<SemanticZoom Style="{StaticResource GenericJumpListStyle}"
              Margin="19,0,0,0">
    <SemanticZoom.ZoomedInView>
        <ListView ItemsSource="{Binding Collection.View}">
            <ListView.GroupStyle>
                <GroupStyle HeaderTemplate="{StaticResource GenericGroupHeaderTemplate}"
                            HeaderContainerStyle="{StaticResource JumpListListHeaderContainerStyle}"
                            HidesIfEmpty="True" />
            </ListView.GroupStyle>
            <ListView.ItemTemplate>
                <!--Your item datatemplate here-->
            </ListView.ItemTemplate>
        </ListView>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <ListView ItemsSource="{Binding Collection.View.CollectionGroups}"
                  Style="{StaticResource GenericJumpListPickerStyle}">
        </ListView>
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

C#

To generate your groups that’s compatible with this JumpList setup, you can manually group and order your items in a list of JumpListGroups but you can use my JumpListHelper class to do that easily for you. Again, this helper class is included in the sample project but you can just copy the source code below:

public static class JumpListHelper
{
    /// <summary>
    /// Groups and sorts into a list of generic groups based on a selector.
    /// </summary>
    /// <typeparam name="TSource">Type of the items in the list.</typeparam>
    /// <typeparam name="TSort">Type of value returned by sortSelector.</typeparam>
    /// <typeparam name="TGroup">Type of value returned by groupSelector.</typeparam>
    /// <param name="source">List to be grouped and sorted</param>
    /// <param name="sortSelector">A selector that provides the value that items will be sorted by.</param>
    /// <param name="groupSelector">A selector that provides the value that items will be grouped by.</param>
    /// <param name="isSortDescending">Value indicating to sort groups in reverse. Items in group will still sort ascending.</param>
    /// <returns>A list of JumpListGroups.</returns>
    public static List<JumpListGroup<TSource>> ToGroups<TSource, TSort, TGroup>(
        this IEnumerable<TSource> source, Func<TSource, TSort> sortSelector,
        Func<TSource, TGroup> groupSelector, bool isSortDescending = false)
    {
        var groups = new List<JumpListGroup<TSource>>();

        // Group and sort items based on values returned from the selectors
        var query = from item in source
                    orderby groupSelector(item), sortSelector(item)
                    group item by groupSelector(item) into g
                    select new { GroupName = g.Key, Items = g };

        // For each group generated from the query, create a JumpListGroup
        // and fill it with its items
        foreach (var g in query)
        {
            JumpListGroup<TSource> group = new JumpListGroup<TSource>();
            group.Key = g.GroupName;
            foreach (var item in g.Items)
                group.Add(item);

            if (isSortDescending)
                groups.Insert(0, group);
            else
                groups.Add(group);
        }

        return groups;
    }

    /// <summary>
    /// Groups and sorts into a list of alpha groups based on a string selector.
    /// </summary>
    /// <typeparam name="TSource">Type of the items in the list.</typeparam>
    /// <param name="source">List to be grouped and sorted.</param>
    /// <param name="selector">A selector that will provide a value that items to be sorted and grouped by.</param>
    /// <returns>A list of JumpListGroups.</returns>
    public static List<JumpListGroup<TSource>> ToAlphaGroups<TSource>(
        this IEnumerable<TSource> source, Func<TSource, string> selector)
    {
        // Get the letters representing each group for current language using CharacterGroupings class
        var characterGroupings = new CharacterGroupings();

        // Create dictionary for the letters and replace '...' with proper globe icon
        var keys = characterGroupings.Where(x => x.Label.Count() >= 1)
            .Select(x => x.Label)
            .ToDictionary(x => x);
        keys["..."] = "\uD83C\uDF10";

        // Create groups for each letters
        var groupDictionary = keys.Select(x => new JumpListGroup<TSource>() { Key = x.Value })
            .ToDictionary(x => (string)x.Key);

        // Sort and group items into the groups based on the value returned by the selector
        var query = from item in source
                    orderby selector(item)
                    select item;

        foreach (var item in query)
        {
            var sortValue = selector(item);
            groupDictionary[keys[characterGroupings.Lookup(sortValue)]].Add(item);
        }

        return groupDictionary.Select(x => x.Value).ToList();
    }
}

The helper class generates a list of JumpListGroup objects that will also need to be in your project:

public class JumpListGroup<T> : List<object>
{
    /// <summary>
    /// Key that represents the group of objects and used as group header.
    /// </summary>
    public object Key { get; set; }

    public new IEnumerator<object> GetEnumerator()
    {
        return (System.Collections.Generic.IEnumerator<object>)base.GetEnumerator();
    }
}

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