在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去掉,看到的结果就是很多项,所以我觉得我的猜测还是挺靠谱的。
这里只是简单阐述了这东西怎么用,上面有个链接是研究它内部的,有兴趣的小伙伴可以好好研究下,我也会找时间来补充下研究结果,如果有空的话~