UWP 的 LongListSelector

  • 149
  • 0
  • UWP
  • 2016-04-23

想在 UWP 開發類似以前 WP 的 LongListSelector控制項

以前的 Windows Phone 有個常用的控制項,就是 LongListSelector

長的就像是

LongListSelector圖片來源https://msdn.microsoft.com/dynimg/IC619152.png

不過在 UWP 就沒有這控制項了,但是也可以透過不同的方式達到一樣的效果,主要就是靠 SemanticZoom 來達成。

我們就先開一個 UWP 的專案,然後建立基本資料的類別 AccountItem,用來簡單表示帳號資料

public class AccountItem {
    public string Name { get; set; }
    public int Score { get; set; }
}

然後產生模擬資料

public class DataManager {
    public static ObservableCollection<AccountItem> DataList { get; set; } = new ObservableCollection<AccountItem> {
        new AccountItem { Name="Tom", Score = 10 },
        new AccountItem { Name="Help", Score = 11 },
        new AccountItem { Name="Eric", Score = 3 },
        new AccountItem { Name="Emma", Score = 4 },
        new AccountItem { Name="Jack", Score = 8 },
        new AccountItem { Name="Coco", Score = 14 },
        new AccountItem { Name="Joe", Score = 2 },
        new AccountItem { Name="Eva", Score = 8 },
        new AccountItem { Name="May", Score = 9 },
        new AccountItem { Name="Cindy", Score = 4 },
        new AccountItem { Name="Wei", Score = 14 },
    };

    public ObservableCollection<IGrouping<string, AccountItem>> AlphaGroups { get; set; }

    public DataManager() {
        var list = from f in DataList
                   group f by f.Name[0].ToString() into g
                   orderby g.Key
                   select g;
        AlphaGroups = new ObservableCollection<IGrouping<string, AccountItem>>(list);
    }
}

在 DataManager 的建構式裡,會根據 Name 的第一個字分組相關的資料,到此我們基本的資料都建立完成,接著就來看 UI 怎麼設計

我們先將 SemanticZoom 拉到畫面裡,設定好位置

預設的 Xaml 會包含兩個 GridView

​<SemanticZoom>
    <SemanticZoom.ZoomedInView>
        <GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False"/>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <GridView ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False"/>
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

我們將兩個 GridView 都改成 ListView,ZoomedInView 就是資料列表的那個畫面,而 ZoomedOutView 就是 Key 選單的那個畫面

然後在 Page.Resources 的地方加上

    <local:DataManager x:Key="DataManager"/>
    <CollectionViewSource x:Key="GroupDatas" Source="{Binding AlphaGroups, Source={StaticResource DataManager}}" IsSourceGrouped="True"/>

第一行將 DataManager 設成靜態資源

第二行就是使用 DataManager.AlphaGroups 來產生 CollectionViewSource,因為我們的 AlphaGroups 已經群組化了,所以 IsSourceGrouped 設為 True

接著就是設定 Header 和 Item 的 Template 了。

在 Page.Resource 內加上

<DataTemplate x:Key="GroupHeaderDataTemplate">
    <Grid>
        <TextBlock Text="{Binding Key}" Style="{StaticResource TitleTextBlockStyle}"/>
    </Grid>
</DataTemplate>
<DataTemplate x:Key="AccountDataTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}"/>
        <TextBlock Text=":"/>
        <TextBlock Text="{Binding Score}"/>
    </StackPanel>
</DataTemplate>

注意 Binding 的欄位名稱,在 GroupHeaderDataTemplate 他會傳入 AlphaGroups 裡的項目,也就是 IGrouping<string, AccountItem> 物件,所以我們 Binding Key 這個欄位

而在 AccountDataTemplate 裡,是傳入 IGrouping<string, AccountItem> 物件裡面的項目,也就是 AccountItem 物件,所以我們 Binding Name 和 Score

接著將 ZoomedInView 內的 ListView 改寫成

<ListView ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False" ItemsSource="{Binding Source={StaticResource GroupDatas}}" ItemTemplate="{StaticResource AccountDataTemplate}">
    <ListView.GroupStyle>
        <GroupStyle HeaderTemplate="{StaticResource GroupHeaderDataTemplate}"/>
    </ListView.GroupStyle>
</ListView>

也就是 GroupStyle 的 HeaderTemplate 使用 GroupHeaderDataTemplate,而 ListView 的 ItemTemplate 使用 AccountDataTemplate。

執行時畫面就會如下圖

當我們點選 C,E,H 等 Key 的地方,就會觸發 SemanticZoom,切換成 ZoomedOutView 的畫面,所以接著就來做 ZoomedOutView 裡的 ListView

一樣在 Page.Resource 裡加上

<DataTemplate x:Key="ZoomOutHeaderDataTemplate">
    <Grid>
        <TextBlock Text="{Binding Group.Key}" Style="{StaticResource HeaderTextBlockStyle}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</DataTemplate>

要注意這裡 Binding 的欄位是 Group.Key,

另外在 ZoomedOutView 的地方將 ListView 改寫如下

<SemanticZoom.ZoomedOutView>
    <ListView ScrollViewer.IsHorizontalScrollChainingEnabled="False" ScrollViewer.IsVerticalScrollChainingEnabled="False" ItemsSource="{Binding CollectionGroups, Source={StaticResource GroupDatas}}" ItemTemplate="{StaticResource ZoomOutHeaderDataTemplate}"/>
</SemanticZoom.ZoomedOutView>

這裡也要注意的是 ItemSource Binding 的欄位是 CollectionGroups,這是 CollectionViewSource 裡的一個包含群組的特殊屬性,因此在設定 ItemTemplate 時,傳入的是群組,

這就是為什麼上面的 ZoomOutHeaderDataTemplate 要用 Group 欄位取得值了。

執行程式,我們可以點選表頭的大寫英文字母,就會在 ZoomedOutView 和 ZoomedInView 之間切換,其行為模式就和之前的 LongListSelector 控制項相同了!

範例下載