娥搽裙 发表于 2026-2-10 18:50:00

Avalonia.Controls.DataGrid自动合并列

Winform在用的DataGridView修改为通过线条和透明的方式实现了合并列的效果。一段时间也在留意Avalonia.Controls.DataGrid是否也有类似的做法。一直没有心思去看那些代码,水平有限,实在搞不懂XML/Content一类如何实现绘制内容的。借着AI的帮助终于能试着去修改了。
让AI从DataGrid的以下方法入手
      private void AddNewCellPrivate(DataGridRow row, DataGridColumn column)      {            DataGridCell newCell = new DataGridCell();            PopulateCellContent(                isCellEdited: false,                dataGridColumn: column,                dataGridRow: row,                dataGridCell: newCell);            if (row.OwningGrid != null)            {                newCell.OwningColumn = column;                newCell.IsVisible = column.IsVisible;                if (row.OwningGrid.CellTheme is {} cellTheme)                {                  newCell.SetValue(ThemeProperty, cellTheme, BindingPriority.Template);                }            }            row.Cells.Insert(column.Index, newCell);                        // 智能AutoMerge逻辑:比较当前行和下一行的数据            //ApplySmartAutoMerge(row, column, newCell);      }最后发现,DataGrid并没有为每行数据创建DataGridRow/DataGridCell,且还会复用这些创建出来的DataGridCell显其他行的数据。就是说上面的方法只是开始的显示内容是可预测的。
多次尝试后,发现绘制前都会调用DataGridCell的EnsureGridLine方法,于是将合并的代码主要放在其中
internal void EnsureGridLine(DataGridColumn lastVisibleColumn){    if (OwningGrid != null && _rightGridLine != null)    {      if (OwningGrid.VerticalGridLinesBrush != null && OwningGrid.VerticalGridLinesBrush != _rightGridLine.Fill)      {            _rightGridLine.Fill = OwningGrid.VerticalGridLinesBrush;      }      //忽略其他代码
      // 调用DataGrid的CheckCellToMerge方法    var (isSameAsPrevious, isSameAsNext) = OwningGrid?.CheckCellToMerge(this) ?? (false, false);      // 根据不同的组合情况处理底边框和透明度    HandleMergeResult(isSameAsPrevious, isSameAsNext);}至此,DataGrid决定如何合并,返回当前行与上一行和下一行的数据是否可以合并(现在只是简单的比较当前列的内容是否一致)。
https://img2024.cnblogs.com/blog/12683/202602/12683-20260210174136165-1383757098.png
有一个小小的问题,在滚动时合并列可能会显示空白。虽说在用的winform版的datagridview也有这个小问题。但新的东西多少有点改进,对吧。于是我向AI发出要求。最大的帮助就是判断是否是当前显示的第一列的方法了。
/// /// 判断指定行是否为可视区域的第一行/// /// 要检查的行/// true表示是可视区域的第一行,false表示不是public bool IsFirstVisibleRow(DataGridRow row){    if (_rowsPresenter == null || row == null)      return false;            // 遍历可视区域的所有行,找到索引最小的行    int firstVisibleRowIndex = int.MaxValue;    foreach (Control element in _rowsPresenter.Children)    {      if (element is DataGridRow visibleRow && visibleRow.IsVisible)      {            firstVisibleRowIndex = Math.Min(firstVisibleRowIndex, visibleRow.Index);      }    }      // 如果指定行索引等于可视区域最小索引,则为第一行    return row.Index == firstVisibleRowIndex;}人工分析后发现,DataGridCell的EnsureGridLine不知为何只是lastVisibleColumn有调用,并不是行中的全部列。滚动的刷新由DataGridCellsPresenter发起,看以下方法
internal void EnsureFillerVisibility(){    DataGridFillerColumn fillerColumn = OwningGrid.ColumnsInternal.FillerColumn;    //忽略其他代码    // This must be done after the Filler visibility is determined.This also must be done    // regardless of whether or not the filler visibility actually changed values because    // we could scroll in a cell that didn't have EnsureGridLine called yet    DataGridColumn lastVisibleColumn = OwningGrid.ColumnsInternal.LastVisibleColumn;    if (lastVisibleColumn != null)    {      DataGridCell cell = OwningRow.Cells;      cell.EnsureGridLine(lastVisibleColumn);//不知道为什么只是最后一列需要执行。    }    // 检查是否为首行显示,如果是则清除合并单元格的透明度    bool isFirstVisualRow = (OwningGrid?.IsFirstVisibleRow(OwningRow) == true);    foreach (DataGridCell cell in OwningRow.Cells)    {      cell?.ClearMergeOpacity(isFirstVisualRow);//否的时候,可能需要恢复透明度    }}好了,这就是全部修改。代码在gitee
https://gitee.com/kevin2y/Avalonia.Controls.DataGrid/tree/feature/auto-merge-enhancement
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

邹弘丽 发表于 2026-2-17 12:25:00

东西不错很实用谢谢分享

林鱼 发表于 2026-2-19 12:12:18

这个有用。

郦惠 发表于 2026-2-25 11:38:04

yyds。多谢分享

蚬蕞遂 发表于 2026-3-2 11:41:52

这个好,看起来很实用

印萍 发表于 2026-3-2 14:34:56

这个有用。

零幸 发表于 2026-3-11 09:09:00

收藏一下   不知道什么时候能用到

骆贵 发表于 4 天前

分享、互助 让互联网精神温暖你我

轮达 发表于 4 天前

这个有用。

洪势 发表于 4 天前

不错,里面软件多更新就更好了

供挂 发表于 前天 21:24

谢谢分享,辛苦了

庾签 发表于 3 小时前

过来提前占个楼
页: [1]
查看完整版本: Avalonia.Controls.DataGrid自动合并列