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
相关产品推荐
相关产品推荐

