How to create a ListBox with grouped items and a jump list

 

In WPF, you can archive this functionality with a CollectionView and the GroupStyle dependency property of th ListBox. Unfortunately, neigther of them are currently available on WP7. Therefore I created both, an implementation of ICollectionView and the JumpListBox which subclasses the ListBox by adding a GroupStyle as well as a GroupItemTemplate and some other additions which are explained later.

To group a list, you first need a JumpListCollectionView which is passed to the JumpListBox as the ItemsSource. JumpListCollectionView has the SourceCollection property which is the source for the output to group, filter and even sort (note that sorting is currently not implemented). To group the result, you additionally need to specify a subclassed GroupDescription. This class will allow you to specify the criteria of how to group the data:

 

public class ItemGroupDescripton : GroupDescription 
{ 
     /// <summary> 
     /// Determines the group for a specific item. 
     /// </summary> 
     /// <param name="item">Data item for which to determine the group. In this case this class is of type ItemViewModel.</param> 
     /// <param name="level">Currently, only 0 level is supported.</param> 
     /// <param name="culture">Culture for culture specific determination (ignored here).</param> 
     /// <returns>Gets the group key for the given item.</returns> 
     public override object GroupNameFromItem(object item, int level, System.Globalization.CultureInfo culture) 
     { 
         ItemViewModel m = item as ItemViewModel; 
         string s = m.LineOne; 
         if (string.IsNullOrEmpty(s)) return "#"; 
         char c = char.ToLower(s[0]); 
         return c.ToString(); 
     }
     /// <summary> 
     /// Since the jump list is supposed to show all letters from # to z and not only those who are indeed available, 
     /// all possible groups from # to z are added at this place. 
     /// </summary> 
     public ItemGroupDescripton() 
         : base() 
     { 
         foreach(char c in "#abcdefghijklmnopqrstuvwxyz") 
         { 
             this.GroupNames.Add(c.ToString()); 
         } 
     } 
} 

This implementation expects a collection of ItemViewModel classes as data source. The GroupNameFromItem method now analyzes the data and returns an objects which represents the key for the group to which this item belongs. Usually, the groups are populated automatically depending on the different groups which are detected. But for the JumpListGroup you notice, that the jump list does not only show the available groups in the source collection, but also other groups which are disabled to select.
To archive this, we also must populate the ItemGroupDescription.GroupNames property with all possible groups. This is done at the constructor with this code:

 

     public ItemGroupDescripton() 
         : base() 
     { 
         foreach(char c in "#abcdefghijklmnopqrstuvwxyz") 
         { 
             this.GroupNames.Add(c.ToString()); 
        }

 

 

Note: ICollectionView and GroupDescription are standard classes in WPF and the odyssey implementaion is 1:1, so you can find more information of how to use them on MSDN and any other source about this topics.

 

Now that we have an source for the JumpListBox we can use it as ItemsSource, usually as a MVVM via binding. By default, the group is visualized as a 62x62 pixel sized tile, but you can change it in xaml by adding the following code inside JumpListBox:

 

<odc:JumpListBox.GroupItemTemplate> 
    <DataTemplate> 
        <!--..add your tempate here:--> 
        <Border Margin="0,6,0,6" Width="100" Height="100" Background="{StaticResource PhoneAccentBrush}"> 
            <TextBlock Text="{Binding Name}" Style="{StaticResource PhoneTextExtraLargeStyle}" 
                    Margin="6,0,0,0" VerticalAlignment="Bottom" /> 
    </DataTemplate> 
</odc:JumpListBox.GroupItemTemplate>

 

This example would change the tile to a size of 100x100 pixels.
When you tap on a group, the jump list opens up to choose any of the groups to quick jump. By default this list is implemented as a wrap panel of 4x7 tiles, and also customizable by modifying the JumpListItemTemplate:

 

<odc:JumpListBox.JumpListItemTemplate> 
    <DataTemplate> 
        <Grid> 
            <Border Margin="5"  Width="470" Height="94" Background="{StaticResource PhoneAccentBrush}" 
                    Visibility="{Binding IsEmpty, Converter={StaticResource boolToNegVis}}"> 
                <TextBlock Text="{Binding Name}" Style="{StaticResource PhoneTextExtraLargeStyle}" 
                        Margin="6,0,0,0" VerticalAlignment="Bottom" Foreground="White" /> 
            </Border> 
            <Border Margin="5" Width="470" Height="94" Background="{StaticResource PhoneChromeBrush}" 
                    Visibility="{Binding IsEmpty, Converter={StaticResource boolToVis}}"> 
                <TextBlock Text="{Binding Name}" Style="{StaticResource PhoneTextExtraLargeStyle}" 
                        Margin="6,0,0,0" VerticalAlignment="Bottom" 
                        Foreground="{StaticResource PhoneDisabledBrush}" /> 
            </Border> 
        </Grid> 
    </DataTemplate> 
</odc:JumpListBox.JumpListItemTemplate>
 

This example would change the tile size to 470x94 pixel. As it is within a WrapPanel, this would cause the jump list to render only one tile per column in landscape mode.
Finally you can only change the jump list style itself as followed:

 

<odc:JumpListBox.JumpListStyle> 
    <Style> 
        <Setter Property="JumpListStyle"> 
            <Setter.Value> 
                <Style TargetType="ListBox"> 
                    <Setter Property="Padding" Value="15" /> 
                    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" /> 
                    <Setter Property="Background" Value="{StaticResource dark}" /> 
                    <Setter Property="ItemsPanel"> 
                        <Setter.Value> 
                            <ItemsPanelTemplate> 
                                <StackPanel/> 
                            </ItemsPanelTemplate> 
                        </Setter.Value> 
                    </Setter> 
                </Style> 
            </Setter.Value> 
        </Setter> 
    </Style> 
</odc:JumpListBox.JumpListStyle>
 

This example would change the WrapPanel which is used for layot in a StackPanel.

Last edited Oct 24, 2010 at 11:46 PM by Tom69, version 4

Comments

No comments yet.