想在 UWP 開發類似以前 WP 的 LongListSelector控制項
以前的 Windows Phone 有個常用的控制項,就是 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 控制項相同了!