在wpf中,我们也曾出现过一种情况,就是一个集合A中包含2中类型的集合,Men和Women,然后Men中又包含了一堆men的数据,women中也一样,这样的一种分类集合,我们在WPF中运用的不多,在wpf中基本都是简单的集合绑定,没有牵扯到所谓的分类集合,但是在Win8 app中,这个问题就不可避免了,比如我们打开手机可以看到的app管理页面,其中最顶层应该是ABCDEFG这样的字母导航,当你按了某个字母,自动会跳转到该字母打头的app集,这样的实现,表面上看很复杂,其实用CollectionViewSource与SemanticZoom的结合运用,就会变得很简单。
首先介绍下CollectionViewSource:
这东西网上介绍的也不多,相关帖子也就那么点,说的清楚的也不是很多,它的作用其实就是将我们上面提到的A集合进行分类管理,当他接受到一个A集合,他会自动将里面的内容分成2个Group,就是我们所谓的Men和Women。
有关CollectionViewSource,他之中包含以下属性,不高兴手打就copy来了:
CollectionViewSource是专为数据绑定有UI视图互动而设的,尤其是对于要实现分组的情况下,
更需要它。CollectionViewSource的几个重要的属性:
Source是设置分组后的数据源,数据源就是通过上面的Linq进行转换处理。
IsSourceGrouped属性指示是否允许分组,我试过只有设置允许分组才能看到前面的截图效果。
ItemsPath是分组后,组内部所包含列表的属性路径,即上面Linq中CityList.可以查看它的类型
有点难懂,我们直接用sourc来看,首先我们定义个source类,里面定义我们需要的data source:
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SemanticZoomSample { public enum Gender { Men, Women } public class Person { public int ID { get; set; } public string Name { get; set; } public Gender PersonGender { get; set; } public string Discription { get; set; } } public class PeopleGroup { public string GroupTitle { get; set; } public IList<Person> PeopleInfos { get; set; } public PeopleGroup(string _groupTitle, IList<Person> _peopleInfos) { this.GroupTitle = _groupTitle; this.PeopleInfos = _peopleInfos; } } public class MyDatas { public static readonly Person[] PeopleDatas = new[] { new Person{ID=1,Name="Maa",PersonGender=Gender.Men,Discription = "Maaaaaaaaaaaaa"}, new Person{ID=2,Name="Mbb",PersonGender=Gender.Men,Discription = "Mbbbbbbbbbbbbbbbb"}, new Person{ID=3,Name="Mcc",PersonGender=Gender.Men,Discription = "Mccccccccccccc"}, new Person{ID=4,Name="Mdd",PersonGender=Gender.Men,Discription = "Mdddddddddddddd"}, new Person{ID=5,Name="Mee",PersonGender=Gender.Men,Discription = "Meeeeeeeeeeeeeeee"}, new Person{ID=6,Name="WMaa",PersonGender=Gender.Women,Discription = "WMaaaaaaaaaaaaaaaa"}, new Person{ID=7,Name="WMbb",PersonGender=Gender.Women,Discription = "WMbbbbbbbbbbbbbbb"}, new Person{ID=8,Name="WMcc",PersonGender=Gender.Women,Discription = "WMcccccccccccccccc"}, new Person{ID=9,Name="WMdd",PersonGender=Gender.Women,Discription = "WMddddddddddddddd"}, new Person{ID=10,Name="WMee",PersonGender=Gender.Women,Discription = "WMeeeeeeeeeeeee"}, }; public static IList<Person> People { get; set; } public static IList<PeopleGroup> PeopleGroups { get; set; } static MyDatas() { People = new ObservableCollection<Person>(PeopleDatas); PeopleGroups = new ObservableCollection<PeopleGroup> { new PeopleGroup("Men",new ObservableCollection<Person>(PeopleDatas.Where(c=>c.PersonGender == Gender.Men))), new PeopleGroup("Women",new ObservableCollection<Person>(PeopleDatas.Where(c=>c.PersonGender == Gender.Women))), }; } } }
这里看到,我们最终要绑定的集合名字叫:PeopleGroups,所以我们的CollectionViewSource的source属性就是它,
然后就是itemPath,这个听上去很玄,也不知道绑什么,其实这个最简单的理解就是,你的PeopleGroups里哪里包含了所有人的列表信息,itemPath就是谁,也就是说所有Person组成的集合是哪个,itemPath就是哪个,因此这里就是我们的PersonInfos,那我们的预想就完成了,在Xaml中设定成Resource看下:
<CollectionViewSource x:Name="CollectGroup" x:Key="groupPeople" Source="{Binding}" IsSourceGrouped="True" ItemsPath="PeopleInfos"></CollectionViewSource>
x:Name是为了我们后台调试用,所以这里可以不看,这里Source没有绑,其实绑定的就是this.DataContext,当然也可以直接定义个东西绑上去,不过因为myData中满街都是static,所以我们还是老实点在xaml.cs中写吧。
protected override void OnNavigatedTo(NavigationEventArgs e) { this.DataContext = MyDatas.PeopleGroups; //foreach (var item in this.CollectGroup.View.CollectionGroups) //{ // ICollectionViewGroup grp = (ICollectionViewGroup)item; // var tst = grp.Group; //} //this.myGrid.ItemsSource = MyDatas.People; }
在页面载入时候绑定,ok后我们需要研究下上面这段中注释掉的东西,你会发现CollectionViewSource其实是个MVVM架构的东西,具体在
http://www.silverlightchina.net/html/study/WPF/2011/1110/11659.html
所以我们在里面找一下我们的group,就能找到,首先实在CollectionGroups中,有个Group属性,这就是我们需要的分类组了。
接下来我们在SemanticZoom控件中应用:
SemanticZoom控件本身没什么花头,很好用,对应的就是Win8开始页面右下角那个“-”按钮其实,没图当然没jb,我就是没有,你打我啊~
SemanticZoom控件有两个属性需要定义一个ZoomInView,另一个ZoomOutView,前者是大图,后者是缩略图,我觉得这样很清楚,这样我们先看ZoomInView:
<SemanticZoom.ZoomedInView> <GridView Name="myGrid" Margin="50,0,0,0" ItemsSource="{Binding Source={StaticResource groupPeople}}"> <GridView.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Width="600"> <TextBlock Text="{Binding GroupTitle}" Style="{StaticResource HeaderTextStyle}"></TextBlock> <TextBlock Text=" - "></TextBlock> <TextBlock Text="{Binding PeopleInfos.Count}" Style="{StaticResource HeaderTextStyle}"></TextBlock> </StackPanel> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.Panel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"></StackPanel> </ItemsPanelTemplate> </GroupStyle.Panel> </GroupStyle> </GridView.GroupStyle> <GridView.ItemTemplate> <DataTemplate> <StackPanel Width="900"> <TextBlock Text="{Binding Name}" Style="{StaticResource SubheaderTextStyle}" Width="400"></TextBlock> <Border BorderBrush="Yellow" BorderThickness="2"> <StackPanel> <TextBlock Text="{Binding PersonGender}" Style="{StaticResource BodyTextStyle}" Width="400"></TextBlock> <TextBlock Text="{Binding Discription}" Style="{StaticResource BodyTextStyle}" Width="400"></TextBlock> </StackPanel> </Border> </StackPanel> </DataTemplate> </GridView.ItemTemplate> </GridView> </SemanticZoom.ZoomedInView>这个很好理解,自定义GridView中加入了我们需要的集合,然后就是重点:ZoomOutView:
<SemanticZoom.ZoomedOutView> <GridView Margin="50,0,0,0" ItemsSource="{Binding Path=CollectionGroups, Source={StaticResource groupPeople}}"> <GridView.ItemTemplate> <DataTemplate> <Border BorderBrush="Yellow" BorderThickness="2"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Group.GroupTitle}" FontSize="20" Width="400"></TextBlock> </StackPanel> </Border> </DataTemplate> </GridView.ItemTemplate> </GridView> </SemanticZoom.ZoomedOutView>内容少,但是很重要,我们看到ItemSource绑定的path就是CollectionGroups,就是我们上面所说的,其实就是xxx.View.CollectionGroups.
而这里面的Group,就是我们需要的东西,其实Group对应的类就是PeopleGroup,有心的朋友可以看下,所以GroupTitle的绑定就容易了。
这样就能实现我们上面的效果,这里有一个地方存在歧义,为什么ZoomOut中itemsource绑定了Path,而in中没有,其实我猜是如果不指定path,他就默认指到ItemPath,如果指定了,那就另说,不过这只是猜测,我们需要研究,不过如果我们把ZoomOut的Path去掉,看到的结果就是很多项,所以我觉得我的猜测还是挺靠谱的。
这里只是简单阐述了这东西怎么用,上面有个链接是研究它内部的,有兴趣的小伙伴可以好好研究下,我也会找时间来补充下研究结果,如果有空的话~