[Learing in Win8App] CollectionViewSource集合与SemanticZoom控件的结合

时间:2022-03-02 18:36:03

  在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去掉,看到的结果就是很多项,所以我觉得我的猜测还是挺靠谱的。


这里只是简单阐述了这东西怎么用,上面有个链接是研究它内部的,有兴趣的小伙伴可以好好研究下,我也会找时间来补充下研究结果,如果有空的话~