Windows Phone 7 LongListSelector Sample with Accents and Culture support

Recently I’ve made a few posts about how to support different cultures and accents when using the Windows Phone 7 Long List Selector from the Windows Phone Toolkit. So rather than try and explain each bit I decided to finally publish the code showing how the MSDN sample can be altered to support both accented groupings and cultures;

https://wp7llssample.codeplex.com/

The sample is provided as-is, the code is mostly from MSDN with a few tweaks. You should not accept this as production ready code, please carry out your own tests.

Accented grouping

Capture

Japanese grouping

JapaneseGrouping

Japanese Jump List

JapaneseJumpList

Windows Phone Jump List groupings

In a recent post about displaying a longlistselector in wp7 I eluded to code that would need to be correctly localised. Whilst I haven’t had the time to produce the code, I thought this may prove useful in the meantime (Note: the cultures are from wp8 and may change in future releases);
(Edit) – made it a bit easier to consume, shows phonetic support and corrected issue with the a poor cut that chopped the last character

{“sq-AL”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“ar-SA”,”ابتثجحخدذرزسشصضطظعغفقكلمنهوي…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“Az-Latn-AZ”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“be-BY”,”абвгѓґдђеёєжзѕиїјкќлљмнњопрстћуўфхцччџшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“bg-BG”,”абвгѓґдђеёєжзѕиїјкќлљмнњопрстћуўфхцччџшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“ca-ES”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“zh-CN”,”#ABCDEFGHIJKLMNOPQRSTUVWXYZ…”}, \\ SupportsPhonetics False
{“zh-TW”,”ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“hr-HR”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“cs-CZ”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“da-DK”,”#abcdefghijklmnopqrstuvwxyzæøå…”}, \\ SupportsPhonetics False
{“nl-NL”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“en-US”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“en-GB”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“et-EE”,”#abcdefghijklmnopqrsšzžtuvwõäöũxy…”}, \\ SupportsPhonetics False
{“fil-PH”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“fi-FI”,”#abcdefghijklmnopqrstuvwxyzåäö…”}, \\ SupportsPhonetics False
{“fr-FR”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“de-DE”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“el-GR”,”αβγδεζηθικλμνξοπρστυφχψω…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“he-IL”,”אבגדהוזחטיכלמנסעפצקרשת…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“hi-IN”,”अआइईउऊऋएऐऑओऔकखगघचछजझटठडढणतथदधनपफबभमयरलवशषसह…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“hu-HU”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“id-ID”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“it-IT”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“ja-JP”,”アカサタナハマヤラワ…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics True
{“kk-KZ”,”абвгѓґдђеёєжзѕиїјкќлљмнњопрстћуўфхцччџшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“ko-KR”,”ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“lv-LV”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“lt-LT”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“mk-MK”,”абвгѓґдђеёєжзѕиїјкќлљмнњопрстћуўфхцччџшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“ms-MY”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“nb-NO”,”#abcdefghijklmnopqrstuvwxyzæøå…”}, \\ SupportsPhonetics False
{“fa-IR”,”ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهی…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“pl-PL”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“pt-BR”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“pt-PT”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“ro-RO”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“ru-RU”,”абвгдеёжзийклмнопрстуфхцчшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“sr-Latn-CS”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“sk-SK”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“es-ES”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“es-MX”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“sv-SE”,”#abcdefghijklmnopqrstuvwxyzåäö…”}, \\ SupportsPhonetics False
{“th-TH”,”กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“tr-TR”,”#abcçdefgğhıijklmnoöprsştuüvyz…”}, \\ SupportsPhonetics False
{“uk-UA”,”абвгѓґдђеёєжзѕиїјкќлљмнњопрстћуўфхцччџшщъыьэюя…#abcdefghijklmnopqrstuvwxyz”}, \\ SupportsPhonetics False
{“uz-Latn-UZ”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False
{“vi-VN”,”#abcdefghijklmnopqrstuvwxyz…”}, \\ SupportsPhonetics False

How to use wp7 LongListSelector with Blend Sample Data

In my previous post, How to use Blend sample data with a LongListSelector, I described a a step by step approach to allow Blend sample data to be used with the Wp8 LongListSelector. It makes development a lot easier. However, recently I’ve seen people struggling with the Windows Phone 7 toolikit version and so I thought I’d create this little amendment to support wp7.

  1. Follow the wp8 guide from the link above, it won’t compile but don’t worry we’ll correct it
  2. Replace the magic alpha key class with the following (it has some room for improvement, I’ll get to that later);
     
    
    using System.Collections.Generic;
    using System.Globalization;
    
    namespace LLSSample
    {
        public class AlphaKeyGroup<T> : List<T>
        {
            static string SortedLocalGrouping = "#abcdefghijklmnopqrstuvwxyz";
            /// <summary>
            /// The delegate that is used to get the key information.
            /// </summary>
            /// <param name="item">An object of type T</param>
            /// <returns>The key value to use for this object</returns>
            public delegate string GetKeyDelegate(T item);
    
            /// <summary>
            /// The Key of this group.
            /// </summary>
            public string Key { get;  set; }
    
            
            /// <summary>
            /// Public constructor.
            /// </summary>
            /// <param name="key">The key for this group.</param>
            public AlphaKeyGroup(string key)
            {
                Key = key;
            }
    
            public override string ToString()
            {
                return Key;
            }
            /// <summary>
            /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
            /// </summary>
            /// <param name="slg">The </param>
            /// <returns>Theitems source for a LongListSelector</returns>
            private static List<AlphaKeyGroup<T>> CreateGroups(string nameList)
            {
                List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
    
                foreach (char key in nameList.ToCharArray() )
                {
                    list.Add(new AlphaKeyGroup<T>((key.ToString())));
                }
    
                return list;
            }
    
            /// <summary>
            /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
            /// </summary>
            /// <param name="items">The items to place in the groups.</param>
            /// <param name="ci">The CultureInfo to group and sort by.</param>
            /// <param name="getKey">A delegate to get the key from an item.</param>
            /// <param name="sort">Will sort the data if true.</param>
            /// <returns>An items source for a LongListSelector</returns>
            public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
            {
    
                List<AlphaKeyGroup<T>> list = CreateGroups(SortedLocalGrouping);
    
                foreach (T item in items)
                {
                    int index = 0;
                    
                    {
                        string label = getKey(item);
                        index = SortedLocalGrouping.IndexOf(label[0].ToString().ToLower());
                    }
                    if (index >= 0 && index < list.Count)
                    {
                        list[index].Add(item);
                    }
                }
    
                if (sort)
                {
                    foreach (AlphaKeyGroup<T> group in list)
                    {
                        group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
                    }
                }
    
                return list;
            }
    
        }
    }
    
  3. That’s enough, you can carry on following your favourite wp7 LLS tutorial. However, I’ve included the XAML from my sample too;
     
        <phone:PhoneApplicationPage.Resources>
            <DataTemplate x:Key="AddrBookItemTemplate">
                <StackPanel VerticalAlignment="Top">
                    <TextBlock FontWeight="Bold"  Text="{Binding FirstName}" />
                    <TextBlock Text="{Binding LastName}" />
                    <TextBlock Text="{Binding Address}" />
                    <TextBlock Text="{Binding Phone}" />
                </StackPanel>
            </DataTemplate>
            <DataTemplate x:Key="AddrBookGroupHeaderTemplate">
                <Border Background="Transparent" Padding="5">
                    <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" 
             Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
                        <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" 
                FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
                    </Border>
                </Border>
            </DataTemplate>
            <DataTemplate x:Key="GroupItemsTemplateWp7">
                <Border Background="{StaticResource PhoneAccentBrush}" Margin="{StaticResource PhoneTouchTargetOverhang}" Padding="{StaticResource PhoneTouchTargetOverhang}">
                    <TextBlock Text="{Binding Key}" Style="{StaticResource PhoneTextLargeStyle}"/>
                </Border>
            </DataTemplate>
            <ItemsPanelTemplate x:Key="GroupItemsPanelTemplate">
                        <toolkit:WrapPanel Orientation="Horizontal"/>   
            </ItemsPanelTemplate>
        </phone:PhoneApplicationPage.Resources>
    
     
    <toolkit:LongListSelector
                      x:Name="AddrBook"
                      IsFlatList="False"
                      DisplayAllGroups="True"
                      DataContext="{Binding Source={StaticResource LongListSelectorData}}"
                      ItemsSource="{Binding DataSource}"
                      Background="Transparent"
                      GroupHeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"
                      ItemTemplate="{StaticResource AddrBookItemTemplate}" GroupItemTemplate="{StaticResource GroupItemsTemplateWp7}" GroupItemsPanel="{StaticResource GroupItemsPanelTemplate}"
                      />
    
    
  4. Enjoy design time editing in wp7 too 🙂

Ah, about the differences. The original alpha key class uses some nice localisation tricks that provides the jump list and group headers to be correctly grouped depending upon the users culture. This version is stuck with a hard-coded English character set. I’ve left the skeleton of the code the same as the wp8 version so you can implement your own localisation routines. If I have time I’ll publish that a later date. Hopefully there should be enough there to help you get on.

How to use Blend sample data with a LongListSelector

 

The LongListSelector for Windows Phone is a great control. However, it can be a real pain to design especially when you want to use the Sample Data feature of Blend.

For example, you can  create Sample Data in Blend using a string Property called Name. When you drop it onto a List Box you are shown the data at Design time, this is really useful;

image 

However, if you try the same trick with a Long List Selector your are faced with a blank page. If you try to edit any of the templates you are faced with more blank screens. It is far from ideal. So here is one method to make your Long List Selector projects Blend friendly.

1) Create your Sample Data – if you follow my example create the default Blend Sample with a Property called Name using the format for Name

image

2) Follow the MSDN article for creating a Long List Selector, this way you can test the result and be sure you haven’t made any errors, very easy to do. Don’t worry we’ll use our Sample Data soon

3) Once you have a Long List Selector working we’ll do some surgery. Derive a new class based on our SampleDataSource (if you renamed the SampleDataSource when creating it in Blend, you’ll need to use that name)

namespace Expression.Blend.SampleData.SampleDataSource
{
    public class LongListSampleData : SampleDataSource
    {
        public LongListSampleData() : base()
        {
            dataSource = AlphaKeyGroup<Item>.CreateGroups(base.Collection,
                                System.Threading.Thread.CurrentThread.CurrentUICulture,
                                (Item i) => { return i.Name; }, true);
        }
        private List<AlphaKeyGroup<Item>> dataSource;
        public List<AlphaKeyGroup<Item>> DataSource
        {
            get
            {
                return this.dataSource;
            }
        }
    }
}

4) Add a reference to this new Data Source in App.xaml. Add it to the Resources just like the one Blend added for you;

<Application.Resources>
        <SampleData:SampleDataSource x:Key="SampleDataSource" d:IsDataSource="True"/>
        <SampleData:LongListSampleData x:Key="LongListSelectorData" d:IsDataSource="True"/>

5) Change the various data templates binding from using FirstName to Name

<DataTemplate x:Key="AddrBookItemTemplate">
           <StackPanel VerticalAlignment="Top">
               <TextBlock Text="{Binding FirstName}" />
               <TextBlock Text="{Binding Name}" />

6) Add Binding references to the LongListSelector control;

<phone:LongListSelector
                DataContext="{Binding Source={StaticResource LongListSelectorData}}"
                ItemsSource="{Binding DataSource}"

7) Build and run. You should now see something like;

 

image 

8) View it in Blend or Visual Studio designer. Please note, both designers are a bit flaky – especially Blend. You normally have to close any open window showing the page, in fact it’s often easier to just close the apps down and re-open then. You should then be able to view the selector and all of its templates at Design Time!

image