DCSIMG
October 2011 - Posts - Windows DEV ices DEV
Sign in | Join | Help

Windows DEVices DEV

Elad Shaham's Blog

October 2011 - Posts

Windows Phone Jump List Contact Chooser Control

image3One of my favorite controls in my Windows Phone is the built in contacts chooser control. It groups all of my contacts by the first letter and shows them in order. Once you click a letter, it shows a list of the entire alphabet - every letter which has contacts can be clicked and the control scrolls down (or up) so the group is visible. This is in my opinion a user experience which really differentiates Windows Phone from competing platforms.

You can see the jump list functionality in this video:

So the question is, can we make use of this user experience in our own Windows Phone app?

The short answer is no. Unfortunately the Windows Phone SDK does not ship with such a control.
Fortunately, the August 2011 version of the Windows Phone Toolkit includes enhancements to the LongListSelector control which allows grouping of items and the jump list behavior. What’s left for us to do is to join that functionality together with the contacts database and make it work like a chooser control.

In this post I will be sharing the source code of my contact chooser control, a control I needed to create for my “My Assistant” app, a reminder application. If you can’t wait to read the rest of the explanation, you can scroll down and download the source code.

These are the main source files in my project:

  • ContactChooser – the main control to be used by the developer
  • ContactChooserPage – the page which actually does the job of displaying the contact list.
  • ContactGroup and ContactItem – classes which encapsulate the contacts data and adds additional display properties.

Using this control is as easy as adding it to our XAML (first we need to add the XMLNS entry of course) and binding its Value property to our data:

Using ContactChooser
  1. <controls:ContactChooser Value="{Binding SelectedContact}" />

Please notice that the visual definition of the ContactChooser control is defined under Generic.xaml, under the Themes folder. This is the place where Silverlight looks for default control styles. In the new ControlTemplate defined under the default style, the root element being used is a button. Clicking the button navigates to the ContactChooserPage (look under the ShowContactsPage function in the ContactChooserControl).
The rest of the control itself is pretty standard. You can choose to replace the ContactChooserPage by initializing the ChooserPageUri property with the Uri of the new page you wish to use. Notice it will need to implement the IContactChooser interface.

Now lets move on to the ContactChooserPage. What it contains is a LongListSelector control which is configured to group the contacts together by the first letter. In the XAML part you can see how the LongListSelector control is initialized.

First the GroupItemsPanel – the panel responsible for showing the list of groups - is set to be a WrapPanel. This way the groups are stacked one next to the other, and once the line run out a new line is created.

Group Items Panel
  1. <toolkit:LongListSelector.GroupItemsPanel>
  2.     <ItemsPanelTemplate>
  3.         <toolkit:WrapPanel Orientation="Horizontal"/>
  4.     </ItemsPanelTemplate>
  5. </toolkit:LongListSelector.GroupItemsPanel>

Next, the GroupItemTemplate shows how an individual group item needs to look like in jump list mode.

Group Item
  1. <toolkit:LongListSelector.GroupItemTemplate>
  2.     <DataTemplate>
  3.         <Border
  4.             Background="{StaticResource PhoneAccentBrush}"
  5.             Width="99"
  6.             Height="99"
  7.             Margin="6">
  8.             <TextBlock
  9.                 Text="{Binding FirstLetter}"
  10.                 FontFamily="{StaticResource PhoneFontFamilySemiBold}"
  11.                 FontSize="48"
  12.                 Margin="8,0,0,0"
  13.                 Foreground="White"                                        
  14.                 VerticalAlignment="Bottom"
  15.                 />
  16.         </Border>
  17.     </DataTemplate>
  18. </toolkit:LongListSelector.GroupItemTemplate>

The GroupHeaderTemplate defines how a group should look like within the list of items.

Group Header
  1. <toolkit:LongListSelector.GroupHeaderTemplate>
  2.     <DataTemplate>
  3.         <Border Background="Transparent" Margin="12,8,0,8">
  4.             <Border
  5.                 Background="{StaticResource PhoneAccentBrush}"
  6.                 Padding="8,0,0,0"
  7.                 Width="62"
  8.                 Height="62"
  9.                 HorizontalAlignment="Left">
  10.                 <TextBlock
  11.                     Text="{Binding FirstLetter}"
  12.                     Foreground="#FFFFFF"
  13.                     FontSize="48"
  14.                     FontFamily="{StaticResource PhoneFontFamilySemiLight}"
  15.                     HorizontalAlignment="Left"
  16.                     VerticalAlignment="Bottom"
  17.                     />
  18.             </Border>
  19.         </Border>
  20.     </DataTemplate>
  21. </toolkit:LongListSelector.GroupHeaderTemplate>

Finally, the ItemTemplate property holds the template that should be used to display a single contact in the list:

Item Template
  1. <toolkit:LongListSelector.ItemTemplate>
  2.     <DataTemplate>
  3.         <StackPanel Orientation="Horizontal" Margin="10,5,0,5">
  4.             <Border Width="64" Height="64" Background="{StaticResource PhoneChromeBrush}" Margin="0,0,10,0">
  5.                 <Image Source="{Binding Image}" VerticalAlignment="Top"/>
  6.             </Border>
  7.             <TextBlock Text="{Binding Contact.DisplayName}" Margin="0" Style="{StaticResource PhoneTextTitle2Style}" />
  8.         </StackPanel>
  9.     </DataTemplate>
  10. </toolkit:LongListSelector.ItemTemplate>

In the code behind of the ContactChooserPage you can see that once the page is loaded the Search function is called. The search function uses the Contacts database API to retrieve all the contacts.

Retrieving contacts
  1. var contacts = new Contacts();
  2. contacts.SearchAsync(null, FilterKind.None, null);

Once the contacts database returns a result set, the results are grouped together and added to the list of groups.

Grouping the contacts
  1. var items = new List<ContactGroup>();
  2. var groups = new Dictionary<char, ContactGroup>();
  3.  
  4. foreach (var contact in args.Results)
  5. {
  6.     char firstLetter = char.ToLower(contact.DisplayName[0]);
  7.  
  8.     // show # for numbers
  9.     if(firstLetter >= '0' && firstLetter <= '9')
  10.     {
  11.         firstLetter = '#';
  12.     }
  13.  
  14.     // create group for letter if it doesn't exist
  15.     if (!groups.ContainsKey(firstLetter))
  16.     {
  17.         var group = new ContactGroup(firstLetter);
  18.         items.Add(group);
  19.         groups[firstLetter] = group;
  20.     }
  21.  
  22.     // create a contact for item and add it to the relevant group
  23.     var contactItem = new ContactItem(contact);
  24.     groups[firstLetter].Add(contactItem);
  25. }
  26.  
  27. Items = items;

And that’s about it…

image2

image1

Please notice that my Contact Chooser control takes a different approach than the built in one.
First, the built in control lists all the letters of the alphabet, even letter groups with no contacts. In such a case the letter is displayed, but cannot get clicked. In my control only letter groups that contain contacts are displayed.
Second, in the built in control international characters are all grouped under the same symbol. Coming from a different country (Israel), in my control every international character gets its own group.

Have fun with my control (and blog about your experience…)!

You can download the source code from here. Notice that in order to make the solution compile, you will need to install the Windows Phone Toolkit.