zoukankan      html  css  js  c++  java
  • 在XAML中为ItemsControl定义分组,适合mvvm绑定

    可以先参考一下这个文章:

    http://www.cnblogs.com/zoexia/archive/2014/11/30/4134012.html


    step0: 先展示一下最简陋的界面:

    上图是一个控件容器:ListBox,每一项都是一个Student的学生数据,它继承自ItemsControl,所以是可以实现分组的。容器内每个组用Expander可伸缩控件表示。
    请保证已经完全理解图中所有控件和数据的含义,然后再进行下一步。


    step1: 首先,我们从dataContext数据源入手,因为它是根本:

    //我们虚拟一个“学校Id”作为将来的分组依据
    public class Student
    {
          public int Id { get; set; }
          public string Name { get; set; }
          public int SchoolId { get; set; }
    }
    
    //然后在ViewModel里准备数据源
            private ObservableCollection<Student> _Students;
            /// <summary>
            /// 绑定通知,学生列表
            /// </summary>
            public ObservableCollection<Student> Students
            {
                get { return _Students; }
                set
                {
                    if (_Students == value) { return; }
                    _Students = value;
                    NotifyOfPropertyChange(() => Students);
                }
            }

    上述代码用到的是MVVM模式,如果你不熟悉, 请学习一下,推荐“刘铁猛”的那个mvvm入门视频,讲的很棒!
    如果还看不懂,我只能说代码是两块,一块是基础Model,一块是扔在绑定源里的一个支持属性通知的成员。


    step3: 在view里获取绑定源

            <CollectionViewSource x:Key="studentsSource" Source="{Binding Students}">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="SchoolId" />
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>

    由于我们的绑定源(Students)现在需要分组,所以,你需要定义,这里的 CollectionViewSource 是在View里处理列表数据源很好用的一个东西,俗称“数据集的视图”,记住所有的ItemsControl其实数据源都是来自于 CollectionView,意思就是所有的列表控件都有一个“数据集的视图”,以前我们没用过的话,默认都是一个“Default”值,比如,分组功能,那就是GroupStyle.Default。
    我以前也有个让DataGrid支持显示行Index的,就是用到了“数据集的视图”,有兴趣的可以去翻阅。

    <ListBox ItemsSource="{Binding Source={StaticResource studentsSource}}" Height="300" Width="200">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=Name}"/>
                    <TextBlock Text="{Binding Path=Id}"/>
                    <TextBlock Text="{Binding Path=SchoolId}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    这里是为了让ListItem的每一列显示成指定的布局,除了让ItemsSource获取我们自己定义的视图资源,其他并无区别。
    那么,问题来了!(最近挺流行这句话的)分组的布局是用什么显示的呢?答案就是“ItemsControl.GroupStyle”属性了,那下面我们就开始定义一个Style

    <ListBox.GroupStyle>
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type GroupItem}">
                                <Expander IsExpanded="True">
                                    <Expander.Header>
                                        <StackPanel Orientation="Horizontal">
                                            <TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
                                            <TextBlock Text="{Binding ItemCount, StringFormat=数量:{0}}"
                                               VerticalAlignment="Center" Margin="5,0,0,0" />
                                            <Button Content="点我" Margin="5,0,0,0" />
                                        </StackPanel>
                                    </Expander.Header>
                                    <ItemsPresenter />
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </ListBox.GroupStyle>

    既然是为“GroupStyle”属性订制自定义容器,那它的数据源就肯定和“ItemsSource”不一样了,它的类型是“MS.Internal.Data.CollectionViewGroupInternal”,派生自CollectionViewGroup类型。
    我们先看看这个类里为数不多的几个属性:

    Items:我们知道的列表容器里ItemsSource属性绑过来的数据其实经过的那道程序,数据源就来自它。
    ItemCount:其实就是Items属性里面资源的个数。
    Name:分组的名称,其实就是前面绑定的“学校Id”的真实值

    大家也看出来了,其实分组容器是和真实数据无关的(除了组名,也就是学校Id,不过它是在分组之前就给定的,和Items里面的真实值无关)。


    好了,over,其实就是分4小步:

    1,先准备数据源,这里是Students
    2,为数据源添加自定义视图,这里是CollectionViewSource
    3,添加显示列表控件,并获取带视图的源
    4,定义GoupStyle

  • 相关阅读:
    码农的半衰期只有15年?
    微软面试100题2010年版全部答案集锦(转自July)
    大量url,如何去重
    后缀树求最长子字符串
    转 STL hash_map & map
    有n 个长为m+1 的字符串,求前后m个字符匹配所能形成的最长字符串链:利用弗洛伊德算法求最长路径
    获取本机地址信息,遇到小问题...有待解决
    HDOJ 1006
    归并排序
    插入排序的简单实现
  • 原文地址:https://www.cnblogs.com/3Tai/p/4134566.html
Copyright © 2011-2022 走看看