在写一个看新闻软件的时候,用到了SemanticZoom控件,遇到了一些问题,比如如何根据首字母分类,以及放大视图中有数据的和没数据的通过背景色或前景色区分,幸运的是,all solved。
先来个效果图
主要是参考了msdn的一篇博客,地址已经放在参考链接里了。
首先是一个SemanticZoom控件,这个控件有ZoomedInView和ZoomedOutView两种视图。
ZoomedOutView视图就是这个
而ZoomedInView视图就是一个带有列表头的列表的样子,还是上个图好了,我个人不喜欢看一大段的纯文字
首先弄个Model,这里叫Picture
1 public class Picture
2 {
3 public string ImageUri { get; set; }
4 public string Title { get; set; }
5 }
然后再加个ViewModel,叫MainPageViewModel,类里写一个数据集合和加载数据的方法
1 public ObservableCollection<AlphaKeyGroup<Picture>> AllPictures { get; set; }
关于加载数据的方法,很显然,我们要把数据按照Title的首字母分组,按首字母分组说实话我不会,然后我在msdn找到了一个类叫AlphaKeyGroup,这个类可以用来按首字母分组
1 public class AlphaKeyGroup<T> : List<T>AlphaKeyGroup
2 {
3 /// <summary>
4 /// The delegate that is used to get the key information.
5 /// </summary>
6 /// <param name="item">An object of type T</param>
7 /// <returns>The key value to use for this object</returns>
8 public delegate string GetKeyDelegate(T item);
9
10 /// <summary>
11 /// The Key of this group.
12 /// </summary>
13 public string Key { get; private set; }
14
15 /// <summary>
16 /// Public constructor.
17 /// </summary>
18 /// <param name="key">The key for this group.</param>
19 public AlphaKeyGroup(string key)
20 {
21 Key = key;
22 }
23
24 /// <summary>
25 /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
26 /// </summary>
27 /// <param name="slg">The </param>
28 /// <returns>Theitems source for a LongListSelector</returns>
29 private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
30 {
31 List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
32
33 foreach (string key in slg.GroupDisplayNames)
34 {
35 list.Add(new AlphaKeyGroup<T>(key));
36 }
37
38 return list;
39 }
40
41 /// <summary>
42 /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
43 /// </summary>
44 /// <param name="items">The items to place in the groups.</param>
45 /// <param name="ci">The CultureInfo to group and sort by.</param>
46 /// <param name="getKey">A delegate to get the key from an item.</param>
47 /// <param name="sort">Will sort the data if true.</param>
48 /// <returns>An items source for a LongListSelector</returns>
49 public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
50 {
51 SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
52 List<AlphaKeyGroup<T>> list = CreateGroups(slg);
53
54 foreach (T item in items)
55 {
56 int index = 0;
57 if (slg.SupportsPhonetics)
58 {
59 //check if your database has yomi string for item
60 //if it does not, then do you want to generate Yomi or ask the user for this item.
61 //index = slg.GetGroupIndex(getKey(Yomiof(item)));
62 }
63 else
64 {
65 index = slg.GetGroupIndex(getKey(item));
66 }
67 if (index >= 0 && index < list.Count)
68 {
69 list[index].Add(item);
70 }
71 }
72
73 if (sort)
74 {
75 foreach (AlphaKeyGroup<T> group in list)
76 {
77 group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
78 }
79 }
80
81 return list;
82 }
83
84 }
使用的时候这样,CreateGroups方法有三个参数,第一个是要分组的数据,第二个参数是分组的方法,第三个参数是是否排序,该方法返回了一个List<AlphaKeyGroup<Picture>>类型的数据,
1 //按拼音分组
2 List<AlphaKeyGroup<Picture>> groupData = AlphaKeyGroup<Picture>.CreateGroups(
3 picturesList, (Picture s) => s.Title, true);
4
5 foreach (var item in groupData)
6 {
7 AllPictures.Add(item);
8 }
当然首先要在picturesList里加一些示例数据
1 picturesList.Add(new Picture { ImageUri = "http://t3.gstatic.com/images?q=tbn:ANd9GcQ_ih-aN2gxUz435mPC733IFDNhk1vqFQSVKshWMHEtzxKfKqbs", Title = "OOO" });View Code
2 picturesList.Add(new Picture { ImageUri = "http://4.bp.blogspot.com/-v4cAAv3ViZk/T3w0jsZocUI/AAAAAAAACE0/l21tSjKnSUI/s640/Cool_facebook_timeline_covers+%252814%2529.jpg", Title = "ZZZ" });
3 picturesList.Add(new Picture { ImageUri = "http://t3.gstatic.com/images?q=tbn:ANd9GcTv1Kx5oic3I39RTIoAMrFOKQxaIKNtXSNSr5B5bUGsX5mRMMBl_Q", Title = "DDD" });
4 picturesList.Add(new Picture { ImageUri = "http://t0.gstatic.com/images?q=tbn:ANd9GcRFzgy_qOhDZ3GAQVxIOi1oTg8VSToo8hX_0cxoD6ZqUW9K-r9p", Title = "BBB" });
然后开始写UI部分,当然要先把Page的DataContext设置到MainPageViewModel的实例,比较简单这里就不写了, 再在Xaml里加上一个CollectionViewSource,用来给SemanticZoom提供数据,ItemsPath填的是集合属性的名字,至于为什么填这个,看看AlphaKeyGroup类的源码就知道了,里面有个List<T>类型的 InternalList,数据就是被存在这里的,IsSourceGrouped意思是要把AllPictures分组
1 <CollectionViewSource x:Key="CollectionViewSource" IsSourceGrouped="True"
2 ItemsPath="InternalList"
3 Source="{Binding AllPictures}"/>
开始写SemanticZoom
1 <SemanticZoom >SemanticZoom
2 <SemanticZoom.Style>
3 <Style TargetType="SemanticZoom">
4 <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
5 </Style>
6 </SemanticZoom.Style>
7 <!--数据列表-->
8 <SemanticZoom.ZoomedInView>
9 <ListView ItemsSource="{Binding Source={StaticResource CollectionViewSource}}"
10 SelectionMode="None"
11 ShowsScrollingPlaceholders="True"
12 IsItemClickEnabled="True"
13 ItemClick="ListView_ItemClick">
14 <ListView.ItemTemplate>
15 <DataTemplate>
16 <Grid Padding="0,8"
17 BorderThickness="{StaticResource BorderThickness}"
18 BorderBrush="{StaticResource BorderBrush}" >
19 <Grid.ColumnDefinitions>
20 <ColumnDefinition Width="2*"/>
21 <ColumnDefinition Width="3*"/>
22 <ColumnDefinition Width="Auto"/>
23 </Grid.ColumnDefinitions>
24 <Image Grid.Column="0" Stretch="Fill" HorizontalAlignment="Left" >
25 <Image.Source>
26 <BitmapImage UriSource="{Binding imageUri}"/>
27 </Image.Source>
28 </Image>
29 <Grid Grid.Column="1" Margin="5,2">
30 <TextBlock Text="{Binding Title}" VerticalAlignment="Top" TextWrapping="Wrap"/>
31 </Grid>
32 </Grid>
33 </DataTemplate>
34 </ListView.ItemTemplate>
35 <ListView.ItemContainerStyle>
36 <Style TargetType="ListViewItem">
37 <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
38 <Setter Property="Margin" Value="0"/>
39 </Style>
40 </ListView.ItemContainerStyle>
41 <!--列表头-->
42 <ListView.GroupStyle>
43 <GroupStyle HidesIfEmpty="True" >
44 <GroupStyle.HeaderTemplate>
45 <DataTemplate>
46 <TextBlock Text="{Binding Key}" FontSize="25" Foreground="Red"/>
47 </DataTemplate>
48 </GroupStyle.HeaderTemplate>
49 </GroupStyle>
50 </ListView.GroupStyle>
51 </ListView>
52 </SemanticZoom.ZoomedInView>
53 <!--排序列表-->
54 <SemanticZoom.ZoomedOutView>
55 <GridView ItemsSource="{Binding Source={StaticResource CollectionViewSource},Path=CollectionGroups}">
56 <GridView.ItemsPanel>
57 <ItemsPanelTemplate>
58 <WrapGrid MaximumRowsOrColumns="4" VerticalAlignment="Top" Orientation="Horizontal"/>
59 </ItemsPanelTemplate>
60 </GridView.ItemsPanel>
61 <GridView.ItemTemplate>
62 <DataTemplate>
63 <Border Background="{Binding Converter={StaticResource BackgroundConverter}}">
64 <TextBlock Text="{Binding Group.Key}" HorizontalAlignment="Center"
65 VerticalAlignment="Center"
66 Foreground="{Binding Converter={StaticResource ForegroundConverter}}"/>
67 </Border>
68 </DataTemplate>
69 </GridView.ItemTemplate>
70
71 <GridView.ItemContainerStyle>
72 <Style TargetType="GridViewItem">
73 <Setter Property="HorizontalAlignment" Value="Center"/>
74 <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
75 <Setter Property="VerticalAlignment" Value="Center"/>
76 <Setter Property="VerticalContentAlignment" Value="Stretch"/>
77 </Style>
78 </GridView.ItemContainerStyle>
79 <GridView.Template>
80 <ControlTemplate>
81 <ScrollViewer ScrollViewer.VerticalScrollMode="Enabled">
82 <Viewbox Stretch="Uniform" Margin="8" VerticalAlignment="Top"
83 ScrollViewer.VerticalScrollMode="Enabled" StretchDirection="Both" >
84 <ItemsPresenter />
85 </Viewbox>
86 </ScrollViewer>
87 </ControlTemplate>
88 </GridView.Template>
89 </GridView>
90 </SemanticZoom.ZoomedOutView>
91 </SemanticZoom>
注意到排序列表的GridView.ItemTemplate ,用到了两个Converter,即BackgroundConverter和ForegroundConverter
1 <Border Background="{Binding Converter={StaticResource BackgroundConverter}}">
2 <TextBlock Text="{Binding Group.Key}" HorizontalAlignment="Center"
3 VerticalAlignment="Center"
4 Foreground="{Binding Converter={StaticResource ForegroundConverter}}"/>
5 </Border>
我一直想实现在ZoomedOutView里那种有数据的和没数据的用颜色区分的功能,自己写Converter没写出来,然后发现了这个
这两个Converter是系统自带的,用的时候设置好Enabled和Disabled的颜色,有数据的时候显示Enabled的颜色,没有就显示Disabled的颜色
1 <JumpListItemBackgroundConverter x:Key="BackgroundConverter" Enabled="Red"
2 Disabled="Transparent"/>
3 <JumpListItemBackgroundConverter x:Key="ForegroundConverter" Enabled="White" Disabled="Black"/>
附上demo
还有一个待解决的问题,在ZoomOutView中如何将无数据的项变成不可点击状态?既然那两个Converter能知道哪个是没数据的,说明一定有办法,Pending……
参考链接