You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF DataGrid总计行实现:主列重排时同步底部总计列位置

嘿,这个需求我之前做项目的时候刚好碰到过——用两个DataGrid分别承载数据和总计行的方案确实很直观,要实现列位置同步其实核心就是监听主DataGrid的列位置变化事件,然后把列的顺序同步给底部的总计DataGrid就行。下面给你一步步拆解具体实现:

核心实现步骤

1. 先保证两个DataGrid的列结构匹配

不管你是让DataGrid自动生成列,还是手动定义列,都得确保总计DataGrid的列和主DataGrid的列一一对应。比如主DataGrid绑定的是业务DataTable,那总计DataGrid可以直接Clone主表的结构,这样列名、数据类型完全一致,后续同步的时候匹配起来特别省心。

2. 监听主DataGrid的列位置变化事件

WPF的DataGrid自带了ColumnDisplayIndexChanged事件,用户拖动调整列位置时就会触发它。我们只需要给主DataGrid注册这个事件,然后在事件处理方法里做同步操作。

3. 实现列顺序同步逻辑

遍历主DataGrid的每一列,通过列名(或者你自定义的唯一标识,比如Tag属性)找到总计DataGrid中对应的列,然后把主列的DisplayIndex(显示顺序)赋值给总计列的DisplayIndex就搞定了。

代码示例

XAML部分

把两个DataGrid放在同一个容器里(比如StackPanel),给它们命名方便后台操作:

<Grid>
    <StackPanel>
        <!-- 主数据DataGrid -->
        <DataGrid x:Name="MainDataGrid" 
                  AutoGenerateColumns="True"
                  ColumnDisplayIndexChanged="MainDataGrid_ColumnDisplayIndexChanged"
                  Margin="0,0,0,5">
        </DataGrid>
        <!-- 总计行DataGrid -->
        <DataGrid x:Name="TotalDataGrid" 
                  AutoGenerateColumns="True"
                  IsReadOnly="True"
                  HeadersVisibility="None">
            <!-- 隐藏总计DataGrid的表头,因为主DataGrid已经有了,视觉上更统一 -->
        </DataGrid>
    </StackPanel>
</Grid>

C#后台代码

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    // 假设这里已经完成主DataGrid的数据绑定,比如绑定到你的业务DataTable
    var businessTable = GetBusinessDataTable();
    MainDataGrid.ItemsSource = businessTable.DefaultView;

    // 生成总计DataTable并绑定到总计DataGrid
    var totalTable = GenerateTotalTable(businessTable);
    TotalDataGrid.ItemsSource = totalTable.DefaultView;

    // 初始化时同步一次列顺序,避免初始状态下顺序不一致
    SyncColumnOrder();
}

// 生成总计DataTable的方法,根据你的业务需求计算列总计
private DataTable GenerateTotalTable(DataTable sourceTable)
{
    // 克隆主表结构,保证列一致
    DataTable totalTable = sourceTable.Clone();
    DataRow totalRow = totalTable.NewRow();

    // 遍历列计算总计,这里以数值列求和为例
    foreach (DataColumn col in sourceTable.Columns)
    {
        if (col.DataType == typeof(decimal) || col.DataType == typeof(int))
        {
            totalRow[col.ColumnName] = sourceTable.AsEnumerable()
                                                  .Sum(row => row.Field<decimal>(col.ColumnName));
        }
        else
        {
            // 非数值列可以显示"总计"或者其他你想要的文本
            totalRow[col.ColumnName] = "总计";
        }
    }

    totalTable.Rows.Add(totalRow);
    return totalTable;
}

// 列位置变化时触发的事件
private void MainDataGrid_ColumnDisplayIndexChanged(object sender, DataGridColumnEventArgs e)
{
    SyncColumnOrder();
}

// 核心同步方法
private void SyncColumnOrder()
{
    // 先判断两个DataGrid的列数是否一致,避免出错
    if (MainDataGrid.Columns.Count != TotalDataGrid.Columns.Count)
        return;

    // 遍历主DataGrid的列,同步顺序到总计DataGrid
    foreach (DataGridColumn mainCol in MainDataGrid.Columns)
    {
        // 通过列名匹配对应列(因为我们克隆了表结构,列名是一致的)
        var totalCol = TotalDataGrid.Columns.FirstOrDefault(c => c.Header.ToString() == mainCol.Header.ToString());
        if (totalCol != null)
        {
            totalCol.DisplayIndex = mainCol.DisplayIndex;
            // 可选:如果需要同步列的隐藏状态,加上这一行
            // totalCol.Visibility = mainCol.Visibility;
        }
    }
}

// 模拟获取业务数据的方法,替换成你实际的数据逻辑
private DataTable GetBusinessDataTable()
{
    DataTable table = new DataTable();
    table.Columns.Add("ID", typeof(int));
    table.Columns.Add("ProductName", typeof(string));
    table.Columns.Add("Price", typeof(decimal));
    table.Columns.Add("Quantity", typeof(int));

    table.Rows.Add(1, "A产品", 10.5m, 20);
    table.Rows.Add(2, "B产品", 25.8m, 15);
    table.Rows.Add(3, "C产品", 8.2m, 30);
    return table;
}
额外注意事项
  • 如果是手动定义DataGrid列(不是自动生成),记得给总计DataGrid的列设置和主列一致的Header或者Tag,这样匹配的时候不会出错;
  • 如果需要同步列的隐藏/显示状态,只需要在SyncColumnOrder方法里加上totalCol.Visibility = mainCol.Visibility;即可;
  • 要是担心列名重复的情况,可以给每个列设置唯一的Tag值,然后通过Tag来匹配对应列,这样更可靠。

内容的提问来源于stack exchange,提问作者Edgar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:26:42