WPF/C#:如何將資料分組顯示

mingupupup發表於2024-06-17

WPF Samples中的示例

在WPF Samples中有一個關於Grouping的Demo。

該Demo結構如下:

image-20240617105742146

MainWindow.xaml如下:

<Window x:Class="Grouping.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Grouping"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" SizeToContent="Height">
    <StackPanel>

        <StackPanel.Resources>
            <XmlDataProvider x:Key="MyTasks" XPath="Tasks/Task">
                <x:XData>
                    <Tasks xmlns="">
                        <Task Name="Groceries" Priority="2" Type="Home">
                            <Description>Pick up Groceries and Detergent</Description>
                        </Task>
                        <Task Name="Laundry" Priority="2" Type="Home">
                            <Description>Do Laundry</Description>
                        </Task>
                        <Task Name="Email" Priority="1" Type="Work">
                            <Description>Email Clients</Description>
                        </Task>
                        <Task Name="Clean" Priority="3" Type="Work">
                            <Description>Clean my office</Description>
                        </Task>
                        <Task Name="Dinner" Priority="1" Type="Home">
                            <Description>Get ready for family reunion</Description>
                        </Task>
                        <Task Name="Proposals" Priority="2" Type="Work">
                            <Description>Review new budget proposals</Description>
                        </Task>
                    </Tasks>
                </x:XData>
            </XmlDataProvider>
        </StackPanel.Resources>

        <TextBlock Margin="12,5,5,0" FontSize="20" Text="My Task List"/>
        <CheckBox Margin="10,5,5,10" Checked="AddGrouping"
              Unchecked="RemoveGrouping">Group by task type</CheckBox>
        <ItemsControl Margin="10" Name="myItemsControl"
                  ItemsSource="{Binding Source={StaticResource MyTasks}}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <DataTemplate.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="FontSize" Value="18"/>
                            <Setter Property="HorizontalAlignment" Value="Center"/>
                        </Style>
                    </DataTemplate.Resources>
                    <Grid>
                        <Ellipse Fill="Silver"/>
                        <StackPanel>
                            <TextBlock Margin="3,3,3,0"
                         Text="{Binding XPath=@Name}"/>
                            <TextBlock Margin="3,0,3,7"
                         Text="{Binding XPath=@Priority}"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Control.Width" Value="100"/>
                    <Setter Property="Control.Margin" Value="5"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock FontWeight="Bold" FontSize="15"
                         Text="{Binding Path=Name}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ItemsControl.GroupStyle>
        </ItemsControl>
    </StackPanel>
</Window>

其中:

 <StackPanel.Resources>
            <XmlDataProvider x:Key="MyTasks" XPath="Tasks/Task">
                <x:XData>
                    <Tasks xmlns="">
                        <Task Name="Groceries" Priority="2" Type="Home">
                            <Description>Pick up Groceries and Detergent</Description>
                        </Task>
                        <Task Name="Laundry" Priority="2" Type="Home">
                            <Description>Do Laundry</Description>
                        </Task>
                        <Task Name="Email" Priority="1" Type="Work">
                            <Description>Email Clients</Description>
                        </Task>
                        <Task Name="Clean" Priority="3" Type="Work">
                            <Description>Clean my office</Description>
                        </Task>
                        <Task Name="Dinner" Priority="1" Type="Home">
                            <Description>Get ready for family reunion</Description>
                        </Task>
                        <Task Name="Proposals" Priority="2" Type="Work">
                            <Description>Review new budget proposals</Description>
                        </Task>
                    </Tasks>
                </x:XData>
            </XmlDataProvider>
        </StackPanel.Resources>

使用XmlDataProvider來載入和繫結XML資料。

 <ItemsControl Margin="10" Name="myItemsControl"
                  ItemsSource="{Binding Source={StaticResource MyTasks}}">

將MyTasks繫結到ItemsControl。

 <DataTemplate>
                    <DataTemplate.Resources>
                        <Style TargetType="TextBlock">
                            <Setter Property="FontSize" Value="18"/>
                            <Setter Property="HorizontalAlignment" Value="Center"/>
                        </Style>
                    </DataTemplate.Resources>
                    <Grid>
                        <Ellipse Fill="Silver"/>
                        <StackPanel>
                            <TextBlock Margin="3,3,3,0"
                         Text="{Binding XPath=@Name}"/>
                            <TextBlock Margin="3,0,3,7"
                         Text="{Binding XPath=@Priority}"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>

設定資料模板。

跟本次介紹的主題Grouping有關的內容如下:

 <ItemsControl.GroupStyle>
    <GroupStyle>
         <GroupStyle.HeaderTemplate>
             <DataTemplate>
                   <TextBlock FontWeight="Bold" FontSize="15"
                       Text="{Binding Path=Name}"/>
              </DataTemplate>
          </GroupStyle.HeaderTemplate>
     </GroupStyle>
 </ItemsControl.GroupStyle>

image-20240617110520481

ItemsControl.GroupStyle獲取定義每個級別的組的外觀的 GroupStyle 物件集合。

GroupStyle如下所示:

    public class GroupStyle : INotifyPropertyChanged
    {
       
        public static readonly ItemsPanelTemplate DefaultGroupPanel;       
        public GroupStyle();
        public static GroupStyle Default { get; }
        [DefaultValue(0)]
        public int AlternationCount { get; set; }    
        [DefaultValue(null)]
        public Style ContainerStyle { get; set; }
        [DefaultValue(null)]
        public StyleSelector ContainerStyleSelector { get; set; }
        [DefaultValue(null)]
        public string HeaderStringFormat { get; set; }
        [DefaultValue(null)]
        public DataTemplate HeaderTemplate { get; set; }     
        [DefaultValue(null)]
        public DataTemplateSelector HeaderTemplateSelector { get; set; }
        [DefaultValue(false)]
        public bool HidesIfEmpty { get; set; }
        public ItemsPanelTemplate Panel { get; set; }
        protected event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e);
    }
}

這裡設定了GroupStyle.HeaderTemplate,這個元素定義了分組頭的資料模板。資料模板決定了分組頭的具體顯示方式。

 <TextBlock FontWeight="Bold" FontSize="15"
                       Text="{Binding Path=Name}"/>

這裡的Name指的是CollectionViewGroup 類的Name屬性。

image-20240617123709245

CollectionViewGroup 類表示根據 GroupDescriptionsCollectionView 物件建立的組。

MainWindow.cs如下:

 public partial class MainWindow : Window
 {
     private CollectionView _myView;

     public MainWindow()
     {
         InitializeComponent();
     }

     private void AddGrouping(object sender, RoutedEventArgs e)
     {
         _myView = (CollectionView) CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
         if (_myView.CanGroup)
         {
             var groupDescription
                 = new PropertyGroupDescription("@Type");
             _myView.GroupDescriptions.Add(groupDescription);
         }
     }

     private void RemoveGrouping(object sender, RoutedEventArgs e)
     {
         _myView = (CollectionView) CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
         _myView.GroupDescriptions.Clear();
     }
 }

只包含兩個事件處理程式。

進行分組是這樣寫的:

 private void AddGrouping(object sender, RoutedEventArgs e)
     {
         _myView = (CollectionView) CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
         if (_myView.CanGroup)
         {
             var groupDescription
                 = new PropertyGroupDescription("@Type");
             _myView.GroupDescriptions.Add(groupDescription);
         }
     }
_myView = (CollectionView) CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);

雖然CollectionViewSource本身不是一個靜態類,但它提供了一個靜態方法GetDefaultView,這個方法用於獲取與特定資料來源關聯的預設檢視。這種設計允許開發者不必例項化CollectionViewSource物件就能訪問和運算元據源的檢視。

image-20240617112246415

 var groupDescription
     = new PropertyGroupDescription("@Type");
 _myView.GroupDescriptions.Add(groupDescription);

image-20240617112656587

PropertyGroupDescription類描述使用屬性名作為條件對項進行分組。

使用的是這個建構函式:

image-20240617112830520

  = new PropertyGroupDescription("@Type");

在XML和XPath的上下文中,@符號用於引用元素的屬性。

這樣就實現了基於Type屬性進行分組。

  private void RemoveGrouping(object sender, RoutedEventArgs e)
  {
      _myView = (CollectionView) CollectionViewSource.GetDefaultView(myItemsControl.ItemsSource);
      _myView.GroupDescriptions.Clear();
  }

取消分組將_myView.GroupDescriptions清空即可。

該Demo的效果如下:

分組效果

分組前:

image-20240617113824832

分組後:

image-20240617113842413

程式碼來源

[WPF-Samples/Data Binding/Grouping at main · microsoft/WPF-Samples (github.com)]

歡迎關注微信公眾號:DotNet學習交流。

相關文章