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

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

最新文章

  1. VO对象和PO对象的区别
  2. JMM和happens-before原则
  3. 关于dp dip dpi px
  4. html 常用的标签
  5. Linux 问题汇总
  6. 类似网易新闻 title栏 滚动时 文字放大&amp;变色
  7. JS几种数组遍历方式以及性能分析对比
  8. ApacheBench 使用教程
  9. 如何让Eclipse的智能提示像VS一样霸气
  10. windows下批量换程序——运维常用
  11. jQuery ajax error函数(交互错误信息的获取)
  12. pytorch中文文档-torch.nn常用函数-待添加-明天继续
  13. Android Gradle Task
  14. 【编程基础】C语言常见宏定义
  15. OpenGL中VA,VAO,VBO和EBO的区别
  16. centos6中iptables单机网络防火墙的使用
  17. 解读EXPLAIN执行计划中的key_len(转)
  18. CentOs6.7 python2.6升级到2.7.11
  19. SEO优化上首页之搜索引擎用户需求理解
  20. N 秒打开一个新窗口

热门文章

  1. APUE1.11:系统调用 库函数
  2. 条件独立(conditional independence) 结合贝叶斯网络(Bayesian network) 概率有向图 (PRML8.2总结)
  3. 360网站卫士SQL注入绕过案例一个
  4. SpringMVC 如何定义类型转换器
  5. 日期时间JS插件
  6. TensorFlow基础(三)激活函数
  7. _bstr_t可接受多字节、UNICODE字符串,方便用以字符集转换
  8. jar包解压
  9. Xcode命令行作用
  10. 【SQLSERVER学习笔记】分页存储过程+调用