我在前面随笔《在Winform系统开发中,对表格列表中的内容进行分组展示》,介绍了Winform程序中对表格内容进行了分组的展示,在WPF应用中,同样也可以对表格的内容进行分组展示,不过处理方式和Winform有所差异,本篇随笔同样基于SqlSugar开发框架的基础上,实现在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果。
1、回顾Winform的表格分组展示效果
对于常规的二维表格数据,如下所示。
我们根据其中一个字段对表格数据进行分组展示,这样更方便用户对特定数据的归类展示处理。
Winform的界面中,我们基于DevExpress的GridView控件对数据进行分组展示,其中代码如下所示。
//增加汇总字段和显示 var gridView1 = this.winGridViewPager1.gridView1; if (checkGroup.Checked) { this.winGridViewPager1.ShowLineNumber = false; gridView1.IndicatorWidth = 0; gridView1.OptionsView.ShowGroupExpandCollapseButtons = true;//显示折叠的分组 gridView1.OptionsView.AllowCellMerge = true; //允许合并字段 gridView1.OptionsView.GroupDrawMode = GroupDrawMode.Standard; gridView1.GroupSummary.Clear(); gridView1.Columns["Category"].GroupIndex = 0;//对类别进行分组展示 var item = new GridGroupSummaryItem(); item.FieldName = "Id"; item.DisplayFormat = " (合计数量 = {0:n})"; item.SummaryType = DevExpress.Data.SummaryItemType.Count;//Sum、Average等 gridView1.GroupSummary.Add(item); gridView1.ExpandAllGroups(); } else { gridView1.GroupSummary.Clear(); this.winGridViewPager1.ShowLineNumber = true; gridView1.OptionsView.AllowCellMerge = false; }
我们可以看到,只需要实现对 GroupSummary的添加处理即可实现汇总效果的展示。
2、在WPF应用中实现DataGrid的分组显示
在WPF应用中,数据的显示通过DataGrid控件进行展示,默认是没有分组效果的,如果需要分组效果,需要定制表格的分组样式才能达到效果。
我们同样基于SqlSugar开发框架的基础上,基于原料表的数据展示,实现在WPF应用中实现DataGrid的分组显示,实现的效果如下所示。
我们这里根据【类别】字段来进行分组统一,其中分组样式在XAML上定义如下所示。
<DataGrid.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 FontWeight="Bold" Text="类别:" /> <TextBlock FontWeight="Bold" Text="{Binding Name}" /> <TextBlock Text="{Binding ItemCount, StringFormat=' (合计数量 = {0} )'}" /> </StackPanel> </Expander.Header> <ItemsPresenter /> </Expander> </ControlTemplate> </Setter.Value> </Setter> </Style> </GroupStyle.ContainerStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <TextBlock FontWeight="Bold" Text="{Binding Name}" /> </DataTemplate> </GroupStyle.HeaderTemplate> </GroupStyle> </DataGrid.GroupStyle>
如果我们需要控件的虚拟化处理(提高显示性能),那么设置下虚拟化处理属性即可。
<DataGrid x:Name="grid" Grid.Row="1" hc:DataGridAttach.ShowRowNumber="True" AutoGenerateColumns="False" HeadersVisibility="All" IsReadOnly="True" ItemsSource="{Binding ViewModel.Items}" MouseDoubleClick="DataGrid_MouseDoubleClick" RowHeaderWidth="60" SelectionChanged="DataGrid_SelectionChanged" SelectionMode="Extended" VerticalScrollBarVisibility="Auto" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True" >
表格的字段,如没有特殊处理,我们用常用的定义效果即可,如下所示。
<DataGrid.Columns> <DataGridTextColumn Width="SizeToCells" MinWidth="100" Binding="{Binding Id}" Header="ID编号" /> <DataGridTextColumn Width="SizeToCells" MinWidth="100" Binding="{Binding Category}" Header="类别" /> <DataGridTextColumn Width="SizeToCells" MinWidth="100" Binding="{Binding Code}" Header="原料编码" /> .............. </DataGrid.Columns>
对于分组的效果处理,我们后台的C#代码也需要进行一定的适应处理,如下所示。
我们采用MVVM的模式处理查询操作,获得数据并转换为CollectionView后,设置分组信息即可,如下代码所示。
/// <summary> /// 查询处理 /// </summary> [RelayCommand] private async Task Search() { //查询获得视图模型的数据 await this.ViewModel.SearchCommand.ExecuteAsync(null); //把数据集合转换为CollectionView,并设置其GroupDescriptions var viewSource = CollectionViewSource.GetDefaultView(this.ViewModel.Items); if (this.ViewModel.IsUseGroup) { viewSource.GroupDescriptions.Clear(); viewSource.GroupDescriptions.Add(new PropertyGroupDescription("Category")); } this.grid.ItemsSource = viewSource; }
这样就是写了数据的显示和分组处理了。
上面的SearchCommand就是视图模型基类函数的查询获得数据的处理方式。
/// <summary> /// 触发查询处理命令 /// </summary> /// <returns></returns> [RelayCommand] public virtual async Task Search() { //切换第一页 this.PagerInfo.CurrentPageIndex = 1; //查询更新 await GetData(); }
GetData也是视图模型基类函数的通用处理方式,通过分页和条件信息,获得对应的数据记录。
/// <summary> /// 根据分页和查询条件查询,请求数据 /// </summary> /// <returns></returns> public virtual async Task GetData() { //转换下分页信息 ConvertPagingInfo(); var result = await service.GetListAsync(this.PageDto); if (result != null) { this.Items = result.Items?.ToList(); this.PagerInfo.RecordCount = result.TotalCount; } }
3、在WPF应用中实现嵌套明细展示效果
我们这里继续介绍另外一个DataGrid的效果,通过明细展示的方式显示其中一条记录相关联的表格信息,有时候也可以看成是主从关联信息。
单我们单击其中一条记录的时候,展示嵌套表格,展示详细的明细信息,如下效果所示。
这个效果主要是通过定义DataGrid.RowDetailsTemplate进行明细内容的处理的。例如我们定义明细的模板如下所示,其实也就是显示另外一个表格信息。
<DataGrid.RowDetailsTemplate> <DataTemplate> <DataGrid MaxHeight="500" hc:DataGridAttach.ShowRowNumber="True" AlternatingRowBackground="LightBlue" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" RowHeaderWidth="60" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectionUnit="FullRow"> <DataGrid.Columns> <DataGridTextColumn MinWidth="120" Binding="{Binding Name}" Header="显示名称" /> <DataGridTemplateColumn Width="80" Header="图标"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ui:SymbolIcon Width="32" FontSize="32" Symbol="{Binding Icon}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Width="80" Binding="{Binding Seq}" Header="排序" /> <DataGridTextColumn Width="100" Binding="{Binding FunctionId}" Header="功能ID" /> </DataGrid.Columns> </DataGrid> </DataTemplate> </DataGrid.RowDetailsTemplate>
Xaml的结构如下所示。
另外,我们在视图模型中除了定义一级的数据记录外,还定义一个嵌套记录集合对象,如下所示。
/// <summary> /// 编辑的数据列表 /// </summary> [ObservableProperty] private ObservableCollection<MenuInfo>? menuItems; /// <summary> /// 指定父级的子级数据列表 /// </summary> [ObservableProperty] private ObservableCollection<MenuInfo>? detailItems;
这样我们在行选择变化的时候,重新获得明细的记录,然后绑定显示事件即可,如下代码所示。
/// <summary> /// 记录行变化的时候,触发明细记录的获取处理 /// </summary> private async void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { var datagrid = sender as DataGrid; if (datagrid != null) { var item = datagrid!.SelectedItem as MenuInfo; if (item != null) { await ViewModel.GetDetailList(item.Id); } } }
而在页面初始化的时候,我们可以构造一个事件,用来绑定明细记录的绑定显示处理。
//明细记录可见性变化的时候,触发数据的绑定处理事件 this.grid.RowDetailsVisibilityChanged += (s, e) => { var datagrid = s as DataGrid; if (datagrid != null) { var DetailsDataGrid = e.DetailsElement as DataGrid; if(DetailsDataGrid != null) { DetailsDataGrid.ItemsSource = viewModel.DetailItems; } } };
这样就可以正常的显示嵌套明细的记录了。