WPF/C#:顯示分組資料的兩種方式

mingupupup發表於2024-06-19

前言

本文介紹自己在遇到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中的CollectionViewSourcePropertyGroupDescription類來對資料進行分組。

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>

GroupStyleGroupStyle.HeaderTemplate是用來自定義分組頭部的顯示方式。

GroupStyle: 這是一個用於定義分組樣式的元素。它允許你為ui:ListView中的每個分組自定義外觀和行為。在這個元素內部,你可以定義頭部模板(HeaderTemplate)、容器樣式(ContainerStyle)等。
GroupStyle.HeaderTemplate: 這個元素定義了分組頭部的模板。透過這個模板,你可以自定義分組頭部的外觀。

實現的效果如下所示:

image-20240619122143726

基於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中的一個控制元件,中文通常翻譯為“擴充套件器”或“可摺疊控制元件”。它是一個容器控制元件,允許使用者透過點選標題欄來展開或摺疊其內容區域。這種控制元件在使用者介面設計中非常有用,可以用來隱藏或顯示詳細資訊,從而節省螢幕空間。

實現效果如下所示:

image-20240619123207859

image-20240619123228203

回顧

本文介紹了遇到WPF對資料進行分組顯示的需求時,可以選擇的兩種方案。一種方案基於ICollectionView,另一種方案基於IGrouping

基於ICollectionView的方案,在cs程式碼中透過CollectionViewSource.GetDefaultView方法獲得集合的預設檢視,建立一個PropertyGroupDescription類,ICollectionViewGroupDescriptions屬性新增建立的PropertyGroupDescription物件。在xaml程式碼中,除了一般的資料繫結外,還新增了ListView.GroupStyle,設定了 GroupStyle.HeaderTemplate

基於IGrouping的方案,在cs程式碼中,使用LinqGroupBy方法對People集合進行分組。在xaml程式碼中在ListView的資料模板中使用Expander控制元件繫結分組的Key屬性,在Expander控制元件中再包含一個ListView控制元件,繫結每個分組中的資料項。

相關文章