Windows Phone 8的列表控件天生支持分组,就像人脉应用中的类似,可以快速根据拼音首字母定位。在列表视图中点击分组标题后显示所有的组名,点击组名即可定位到这个组。我们自己开发的WP应用也能做到这样的分组功能,但需要一些额外的代码。下面的例子来自我的一个WP应用,有图有真相:

分组视图:

实现LongListSelector分组其实很简单。

1. 首先,你需要一个分组的助手类,这是一个相对标准的类,MSDN上抄来的:

public class Group<T> : List<T>
{
    public Group(string name, IEnumerable<T> items)
        : base(items)
    {
        this.Title = name;
    }

    public string Title
    {
        get;
        set;
    }

    public static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, string> getKeyFunc)
    {
        IEnumerable<Group<T>> groupList = from item in itemList
                                          group item by getKeyFunc(item) into g
                                          orderby g.Key
                                          select new Group<T>(g.Key, g);

        return groupList.ToList();
    }
}

然后,对于你要分组的内容,就能通过getKeyFunc委托来指定依据哪个字段分组了。比如我应用里的电影列表希望根据电影名称进行分组,即MovieInfo.Title,代码就要这样写:

this.GroupedQueryResults = Group<MovieInfo>.GetItemGroups(rawCollection, m => m.Title).ToObservableCollection();

其中,rawCollection是一个未经过分组的IEnumerable<MovieInfo>列表。

2. 在XAML页面里,LongListSelector所绑定的对象需要设置为经过分组的GroupedQueryResults。

<phone:LongListSelector ItemsSource="{Binding GroupedQueryResults, Mode=TwoWay}"
                        LayoutMode="List"
                        IsGroupingEnabled="True"
                        HideEmptyGroups="True"
                        JumpListStyle="{StaticResource MovieListJumpListStyle}"
                        >

IsGroupingEnabled属性必须设置为true,以启用分组功能。

HideEmptyGroups属性为是否隐藏没有数据的组,true为不显示,false为显示。

JumpListStyle是分组视图的样式,我的应用里样式定义如下:

<Style x:Key="MovieListJumpListStyle" TargetType="phone:LongListSelector">
    <!--<Setter Property="GridCellSize"  Value="113,113"/>-->
    <Setter Property="LayoutMode" Value="List" />
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="400" Height="90" Margin="6" >
                    <TextBlock Text="{Binding Title}" 
                               FontFamily="{StaticResource PhoneFontFamilySemiBold}" 
                               FontSize="30" 
                               Padding="6" 
                               Foreground="{Binding Converter={StaticResource ForegroundConverter}}" 
                               VerticalAlignment="Center"/>
                </Border>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

最后,我们还需要指定列表视图中组标题的模板。我的模板如下:

<phone:LongListSelector.GroupHeaderTemplate>
    <DataTemplate>
        <Border Background="Transparent" Padding="5">
            <Border 
                Background="{StaticResource PhoneAccentBrush}" 
                BorderBrush="{StaticResource PhoneAccentBrush}" 
                BorderThickness="2" 
                Height="62" 
                Margin="0,20,0,5" 
                HorizontalAlignment="Left">
                <TextBlock Text="{Binding Title}" 
                           Foreground="{StaticResource PhoneForegroundBrush}" 
                           FontSize="36" 
                           Padding="6" 
                           FontFamily="{StaticResource PhoneFontFamilySemiLight}"
                           HorizontalAlignment="Left" 
                           VerticalAlignment="Center"/>
            </Border>
        </Border>
    </DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>

注意代码里的“{Binding Title}”,这个绑定的就是组名,即刚才Group<T>类里面的Title属性,如果你不希望它叫Title可以直接改Group<T>类。