Update: Want to get the JumpList experience the easy way? Check out my new controls and download them from nuget.

In a previous post, I outlined how to create a fully functioning JumpList in a WinRT WP app. I provided a helper class to do the heavy lifting of grouping and sorting as well as all of the styles and templates needed to get the correct UX so it can be consistent with the OS. While it works and looks great, it’s far from perfect. The JumpList doesn’t properly support globalization, it is unreadable when high contrast mode is enabled on the device, the performance is quite slow, and it doesn’t automatically support landscape orientation.

The good news is that I’ve fixed the high contrast theming and globalization issues. I’ve also managed improve the performance of the JumpList quite a bit. It’s not perfect and it still needs some work but I think it’s a good enough work around to release. The bad news is I still have no elegant solution for orientation changes without writing some code behind or an attached behavior. So let’s focus on the good news and get to fixing on what we can.

The Material

Globalization

This is a relatively straightforward issue that has a relatively straightforward solution. At the time of writing my JumpListHelper class, I attempted to write the ToAlphaGroups method to be as robust as it can be. This meant that it had to handle diacritics (accents above a letter), numbers as a single group, and other characters that can’t be classified (grouped under the globe icon). I wrote everything from scratch and due to time constraints, I only ended up supporting English.

Supporting only English works fine for any Latin script languages (with a-z alphabets). The English Alpha JumpList consist of a group for numbers and symbols under “#,” a group for each of the 26 English letters, and finally a group for everything else shown as a globe icon. Some non-English languages have additional groups specific for their languages and this is where my helper class fails. Even if the phone is set to Japanese, for example, it will throw all Japanese words into the “other” (globe) group. The expected behavior is to correctly group both Latin characters AND Japanese characters.



English only JumpList grouping vs Japanese JumpList grouping on the same collection.

Thanks to Kinnara, a very helpful built in class was made aware to me that will handle this for me called CharacterGrouping. This class will provide the correct set of characters to group strings under for each of the supported languages. Not only that, it even contains a method that will classify the string into the proper group all while handling capitalization, diacritics, and any other string weirdness for me out of the box. So, I rewrote the ToAlphaGroups method using the CharacterGrouping class and now it supports proper dynamic grouping based on the phone’s display language, removed excess code handling diacritics, and works without needing any changes to the existing JumpList styles and templates. To take advantage of this, replace my previous JumpListHelper.cs file with the new one found in my updated sample project.

Supporting High Contrast

By default, all WinRT apps on WP is enabled to support High Contrast mode. This means that the app will switch out the styles to a more stark color palette for better readability. For the most part, the default style does pretty well at handling this automatically. Colors automatically change to white (in dark theme) or black (in light theme) so almost everything seems black and white. Unfortunately, with custom controls and custom styles, some things do not work out properly. You can see this for yourself by going to Settings>Ease of Access and turning on the high contrast toggle. This is what my original JumpList styles and templates look like when you enable high contrast.

Before we go any further, the first thing I did was move all of the JumpList specific styles and templates out into its own XAML file. The JumpList specific styles and templates are already getting pretty long and adding support for high contrast will only make it bigger and more unruly. To start, I created a new folder called “Styles” under “Assets” and then added a new XAML-only file (I added a new text file but renamed it with the extension .xaml).

The file should be blank so we need to add some content to it to get started. The root of the JumpList.xaml file should look like this:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> </ResourceDictionary/>

Previously, I had all of the styles and templates for my JumpLists in my App.xaml resources. I simply moved all of that into the new JumpList.xaml file then referenced it in my App.xaml global resources 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>

Note: Many style and elements were renamed, moved, and reworked. To ensure that my implementation will work for you, I suggest you remove my old styles, templates, and page xaml and re-implement where needed.

Now, let’s actually enable support for high contrast. Essentially, we need to define two ways the JumpList will look: the default look, and the high contrast look. In order to let the OS handle the switch between these two looks automatically, we use a ThemeDictionary. The first ThemeDictionary will be keyed as Default and the second will be keyed as HighContrast for obvious reasons. The OS specifically looks for these keys so don’t go changing it around. The top of our JumpList.xaml styles file will look like this now:

<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" /> </ResourceDictionary> <ResourceDictionary x:Key="HighContrast"> <JumpListItemBackgroundConverter x:Key="JumpListItemBackgroundConverter" /> <JumpListItemForegroundConverter x:Key="JumpListItemForegroundConverter" /> </ResourceDictionary> </ResourceDictionary.ThemeDictionaries> <!-- styles and templates for JumpLists are below this point -->

Notice that I’ve moved the converters needed by the JumpList templates into each of the ThemeDictionaries. If you don’t do this, the app will immediately crash when trying to instantiate the converters. I’m not sure why that happens but it works this way so let’s roll with it.

Now, in each of the ThemeDictionaries, we simply define the values that are different between the two modes and then reference theme in our styles and templates. The OS will automatically apply the correct dictionary at runtime. The most obvious difference between the two are the colors but margins and borders are also different as well. I’ve ensured that it matches the OS’ native look in both mode so here are the values:

<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> <!-- styles and templates for JumpLists are below this point -->

Now that we have defined the values that will change between the two modes, we need to update our templates to use these values. We need to do this for several of the templates to get the look right but here’s one example below. The highlighted lines shows the properties that have been changed to point to the resources we’ve created in the ThemeDictionaries above. To get the full updated styles and templates that support high contrast, download the updated sample project above and grab the JumpList.xaml file.

<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>

Here’s how the JumpList looks after applying our changes in high contrast mode.



Note the app needs to be restarted for all changes to take effect. This is because the Alpha grid uses a converter to get its background and foreground colors and doesn’t refresh automatically.

Performance

While the new SemanticZoom control with the proper style and setup gives us a very good looking JumpList with proper animations and all. The problem is it’s quite a bit slower than the system’s JumpLists when displaying the grid of letters. The purpose of providing a JumpList is to enable the user to jump to a section of the list quickly to get to the items they need quickly. During my test of the Alpha JumpList on a Lumia 920 device, it takes a very noticeable pause the first time the grid of letters is presented and chugs when it’s closed or opened in subsequent times.

The main cause of the performance hit is that the GridView that hosts the letters have to immediately render all 28 squares and then play a fancy animation to present them. The Generic JumpList doesn’t have as much of a problem since it only has present around 12 items in a list so we’ll only be addressing the Alpha JumpList. To speed up the animation performance, what we can do is set the GridView that hosts the 28 letter groups to have a BitmapCache cache mode.

<SemanticZoom.ZoomedOutView> <GridView ItemsSource="{Binding Collection.View.CollectionGroups}" ItemTemplate="{StaticResource AlphaJumpListItemTemplate}" CacheMode="BitmapCache" /> </SemanticZoom.ZoomedOutView>

This forces the GridView to be cached to the GPU and doesn’t get rendered on the CPU every frame redraw. This is only recommended on UIElements that are expected to be static and not animating. This means that this will have a drawback when the Alpha grid can scroll (like in the Japanese JumpList above). Setting its CacheMode property to BitmapCache will allow the reader board animation to play much more smoothly when the Alpha grid but the scrolling of the list (if it’s long enough) will look choppy since it’s being rendered on the GPU. One way around this is to set the Alpha grid’s CacheMode to BitmapCache before it’s shown and set it back to null after it has finished showing. I haven’t come up with a consistent solution using that method yet, but be sure I’ll post it once I’ve perfected it. For now, if you’re willing to deal with the choppy scrolling in non-Latin languages, use BitmapCache.

Note: The sample project will not have the BitmapCache applied to the Alpha grid. You can apply it in your own projects but do so on a case by case basis.

BitmapCache doesn’t solve the initial slowness of showing the Alpha grid though since it still needs to lay out and render all 28+ items. I don’t have a solution for this problem yet either but I’ve managed to simulate a feel of performance increase by invisibly showing the Alpha grid (forcing it to render and layout the items) and then closing it as fast as possible. This is kinda hacky but if I can get it to work consistently, I’ll post the solution along with the dynamic BitmapCache solution in the future.

Update: In addition to using BitmapCache, I’ve updated the styles in the JumpList.xaml file to include a more simple ItemContainerStyle for the Alpha grid provided by Kinnara. It dramatically reduces the visual tree elements that need to be rendered for each Alpha grid item and it dramatically reduces the initial slowness when showing the grid. Implementing this change also changed how the ZoomedOutView property is defined in the SemanticZoom since I combined everything into a ListView style and a GridView style. In pages where you want a JumpList, it should look something like this with the new styles:

<SemanticZoom Style="{StaticResource AlphaJumpListStyle}" Margin="19,0,0,0"> <SemanticZoom.ZoomedInView> <!--The usual ListView stuff with GroupStyles--> </SemanticZoom.ZoomedInView> <SemanticZoom.ZoomedOutView> <GridView ItemsSource="{Binding Collection.View.CollectionGroups}" Style="{StaticResource AlphaJumpListPickerStyle}" /> </SemanticZoom.ZoomedOutView> </SemanticZoom>

<SemanticZoom Style="{StaticResource GenericJumpListStyle}" Margin="19,0,0,0"> <SemanticZoom.ZoomedInView> <!--The usual ListView stuff with GroupStyles--> </SemanticZoom.ZoomedInView> <SemanticZoom.ZoomedOutView> <ListView ItemsSource="{Binding Collection.View.CollectionGroups}" Style="{StaticResource GenericJumpListPickerStyle}" /> </SemanticZoom.ZoomedOutView> </SemanticZoom>