3

在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果

 7 months ago
source link: https://www.cnblogs.com/wuhuacong/p/17989031
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我在前面随笔《在Winform系统开发中,对表格列表中的内容进行分组展示》,介绍了Winform程序中对表格内容进行了分组的展示,在WPF应用中,同样也可以对表格的内容进行分组展示,不过处理方式和Winform有所差异,本篇随笔同样基于SqlSugar开发框架的基础上,实现在WPF应用中实现DataGrid的分组显示,以及嵌套明细展示效果。

1、回顾Winform的表格分组展示效果

对于常规的二维表格数据,如下所示。

8867-20240118124141253-1732309330.png

我们根据其中一个字段对表格数据进行分组展示,这样更方便用户对特定数据的归类展示处理。

8867-20240118131106503-1015349519.png

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的分组显示,实现的效果如下所示。

8867-20240126115818291-1059076410.png

我们这里根据【类别】字段来进行分组统一,其中分组样式在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的效果,通过明细展示的方式显示其中一条记录相关联的表格信息,有时候也可以看成是主从关联信息。

单我们单击其中一条记录的时候,展示嵌套表格,展示详细的明细信息,如下效果所示。

8867-20240126121452845-211186608.png

这个效果主要是通过定义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的结构如下所示。

8867-20240126123420559-2021851607.png

另外,我们在视图模型中除了定义一级的数据记录外,还定义一个嵌套记录集合对象,如下所示。

        /// <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;
            }
        }
    };

这样就可以正常的显示嵌套明细的记录了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK