WPF/C#:如何将数据分组显示

wpf · 浏览次数 : 0

小编点评

本文介绍了WPF中的一个示例,该示例展示如何使用Grouping功能对任务列表进行分组。通过这个示例,我们可以了解如何在WPF应用程序中实现分组功能,并学会如何使用XML和XPath来选择和分组数据。 1. 示例概述 本文首先介绍了WPF Samples中的Grouping Demo,该Demo包含一个名为MainWindow的WPF窗口,窗口中有一个堆叠面板、一个文本框、一个复选框和一个ItemsControl。通过这些控件,我们可以看到如何使用XmlDataProvider加载XML数据,并将数据源绑定到ItemsControl中进行分组显示。 2. 数据绑定与分组 在示例中,我们使用XmlDataProvider来加载XML数据,并将数据源绑定到ItemsControl。通过设置ItemsControl的ItemSource属性为MyTasks,我们将数据源与ItemsControl关联起来。此外,我们还使用了一个DataTemplate来定义分组头的数据模板,从而实现对分组头的自定义显示。 3. GroupStyle与分组头模板 GroupStyle是一个抽象类,它提供了一种方式来定义分组的外观。在这个示例中,我们通过设置GroupStyle.HeaderTemplate来定义分组头的数据模板。这个模板使用TextBlock元素来显示分组名称,并使用FontWeight和FontSize属性来增强文本的可读性。 4. 自定义分组逻辑 在示例中,我们通过添加PropertyGroupDescription来定义一个基于任务类型的自定义分组。这意味着我们将根据每个任务的Type属性对其进行分组。在分组逻辑中,我们可以使用XAML和XPath来选择和过滤数据。 5. 取消分组与数据处理 为了取消分组,我们只需将_ItemsControl.GroupDescriptions属性清空即可。这样,分组头就会消失,只剩下一个没有分组的ItemsControl。 通过这个示例,我们可以了解到如何在WPF应用程序中实现分组功能,并学会如何使用XML和XPath来选择和分组数据。这个示例对于学习WPF中的分组功能非常有帮助,可以帮助我们更好地理解分组逻辑的实现过程。

正文

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学习交流。

与WPF/C#:如何将数据分组显示相似的内容:

WPF/C#:如何将数据分组显示

WPF Samples中的示例 在WPF Samples中有一个关于Grouping的Demo。 该Demo结构如下: MainWindow.xaml如下:

WPF/C#:在DataGrid中显示选择框

前言 在使用WPF的过程中可能会经常遇到在DataGrid的最前或者最后添加一列选择框的需求,今天跟大家分享一下,在自己的项目中是如何实现的。 整体实现效果如下: 如果对此感兴趣,可以接下来看具体实现部分。 实践 假设数据库中的模型如下: public class Person { public i

WPF/C#:数据绑定到方法

在WPF Samples中有一个关于数据绑定到方法的Demo,该Demo结构如下: 运行效果如下所示: 来看看是如何实现的。 先来看下MainWindow.xaml中的内容:

WPF/C#:如何实现拖拉元素

前言 在Canvas中放置了一些元素,需要能够拖拉这些元素,在WPF Samples中的DragDropObjects项目中告诉了我们如何实现这种效果。 效果如下所示: 拖拉过程中的效果如下所示: 具体实现 xaml页面 我们先来看看xaml:

WPF/C#:在WPF中如何实现依赖注入

本文先介绍依赖注入的概念,再解释为什么要进行依赖注入,最后通过 WPF Gallery 这个项目学习如何在WPF中使用依赖注入。

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件,这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法,但是如果真正在项目中使用起来,基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与MVVM模式使用导航功能。实践起来

Azure DevOps(一)基于 Net6.0 的 WPF 程序如何进行持续集成、持续编译

一,引言 我们是否正在为如何快速的编译、部署客户端应用程序而烦恼?这也是博主最近遇到的问题。目前博主所在公司主要做项目级的定制化开发,多以 C/S 架构的 WPF 程序为主,每次到了协助开发团队给实施团队编译好的要测试程序包时,就会出现多人协助,编译、打包好的二进制程序包 pull 最新代码 ,以及

WPF/C#:BusinessLayerValidation

BusinessLayerValidation介绍 BusinessLayerValidation,即业务层验证,是指在软件应用程序的业务逻辑层(Business Layer)中执行的验证过程。业务逻辑层是应用程序架构中的一个关键部分,负责处理与业务规则和逻辑相关的操作。业务层验证的主要目的是确保数

WPF/C#:显示分组数据的两种方式

前言 本文介绍自己在遇到WPF对数据进行分组显示的需求时,可以选择的两种方案。一种方案基于ICollectionView,另一种方案基于IGrouping。 基于ICollectionView实现 相关cs代码: [ObservableProperty] private ObservableColl

WPF/C#:程序关闭的三种模式

ShutdownMode枚举类型介绍 ShutdownMode是一个枚举类型,它定义了WPF应用程序的关闭方式。这个枚举类型有三个成员: OnLastWindowClose:当最后一个窗口关闭或者调用System.Windows.Application.Shutdown方法时,应用程序会关闭。 On