前言
本文介绍自己在遇到WPF对数据进行分组显示的需求时,可以选择的两种方案。一种方案基于ICollectionView
,另一种方案基于IGrouping
。
基于ICollectionView实现
相关cs代码:
[ObservableProperty]
private ObservableCollection<People> people;
public GroupDemoViewModel()
{
People = new ObservableCollection<People>
{
new People { Name = "小一", Class = "1班" },
new People { Name = "小二", Class = "2班" },
new People { Name = "王五", Class = "1班" },
new People { Name = "小红", Class = "2班" },
new People { Name = "小绿", Class = "1班" },
new People { Name = "小刚", Class = "2班" },
};
MyView = CollectionViewSource.GetDefaultView(People);
var groupDescription
= new PropertyGroupDescription("Class");
MyView.GroupDescriptions.Add(groupDescription);
}
这段代码使用了WPF中的CollectionViewSource
与PropertyGroupDescription
类来对数据进行分组。
CollectionViewSource
是一个用于提供数据视图的类,它允许你对数据进行排序、筛选和分组。
GetDefaultView
方法返回一个默认视图,该视图是对People
集合的包装。这个视图可以用于在UI中显示数据,并且可以应用各种视图操作(如排序、筛选和分组)。
PropertyGroupDescription
是一个用于定义分组规则的类。这里创建了一个新的PropertyGroupDescription
对象,并指定分组依据的属性为Class
,这意味着数据将根据这意味着数据将根据People
集合中每个对象的Class
属性值进行分组。
xaml相关代码:
<ui:ListView ItemsSource="{Binding MyView}">
<ui:ListView.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="5"/>
<TextBlock Text="{Binding Class}" Margin="5"/>
</StackPanel>
</DataTemplate>
</ui:ListView.ItemTemplate>
<ui:ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="16"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ui:ListView.GroupStyle>
</ui:ListView>
GroupStyle
和GroupStyle.HeaderTemplate
是用来自定义分组头部的显示方式。
GroupStyle
: 这是一个用于定义分组样式的元素。它允许你为ui:ListView中的每个分组自定义外观和行为。在这个元素内部,你可以定义头部模板(HeaderTemplate)、容器样式(ContainerStyle)等。
GroupStyle.HeaderTemplate
: 这个元素定义了分组头部的模板。通过这个模板,你可以自定义分组头部的外观。
实现的效果如下所示:
基于IGrouping实现
在将数据分组时,我个人比较喜欢使用Linq的GroupBy。
相关cs代码如下:
[ObservableProperty]
private ObservableCollection<People> people;
public IEnumerable<IGrouping<string?,People>> GroupedPeople { get; set; }
public GroupDemoViewModel()
{
People = new ObservableCollection<People>
{
new People { Name = "小一", Class = "1班" },
new People { Name = "小二", Class = "2班" },
new People { Name = "王五", Class = "1班" },
new People { Name = "小红", Class = "2班" },
new People { Name = "小绿", Class = "1班" },
new People { Name = "小刚", Class = "2班" },
};
GroupedPeople = People.GroupBy(x => x.Class);
}
GroupedPeople = People.GroupBy(x => x.Class);
这行代码使用LINQ的GroupBy方法对People集合进行分组。
GroupBy(x => x.Class)
的作用是根据People对象的Class属性的值将这个集合分成多个组。每个组是一个包含有相同Class值的People对象集合。这里的x代表People集合中的每一个People对象,x => x.Class是一个lambda表达式,指定了分组的依据是People对象的Class属性。
GroupBy
方法的结果是一个IEnumerable<IGrouping<string?, People>>
类型的对象。IGrouping<string?, People>
接口表示一个分组,其中string?是分组键的类型(在这个例子中是Class属性的类型),People是集合中元素的类型。每个IGrouping<string?, People>对象包含一个键(Key属性,即Class的值)和一个集合(包含所有具有该Class值的People对象)。
相关xaml代码如下:
<ui:ListView ItemsSource="{Binding GroupedPeople}">
<ui:ListView.ItemTemplate>
<DataTemplate >
<Expander Header="{Binding Key}">
<ui:ListView ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="5"/>
<TextBlock Text="{Binding Class}" Margin="5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ui:ListView>
</Expander>
</DataTemplate>
</ui:ListView.ItemTemplate>
</ui:ListView>
使用了Expander
控件。
Expander
是WPF中的一个控件,中文通常翻译为“扩展器”或“可折叠控件”。它是一个容器控件,允许用户通过点击标题栏来展开或折叠其内容区域。这种控件在用户界面设计中非常有用,可以用来隐藏或显示详细信息,从而节省屏幕空间。
实现效果如下所示:
回顾
本文介绍了遇到WPF对数据进行分组显示的需求时,可以选择的两种方案。一种方案基于ICollectionView
,另一种方案基于IGrouping
。
基于ICollectionView
的方案,在cs代码中通过CollectionViewSource.GetDefaultView
方法获得集合的默认视图,创建一个PropertyGroupDescription
类,ICollectionView
的GroupDescriptions
属性添加创建的PropertyGroupDescription
对象。在xaml代码中,除了一般的数据绑定外,还添加了ListView.GroupStyle
,设置了 GroupStyle.HeaderTemplate
。
基于IGrouping
的方案,在cs代码中,使用Linq
的GroupBy
方法对People集合进行分组。在xaml代码中在ListView
的数据模板中使用Expander
控件绑定分组的Key属性,在Expander
控件中再包含一个ListView
控件,绑定每个分组中的数据项。