找回密码
 立即注册
首页 业界区 业界 Avalonia.Controls.DataGrid自动合并列

Avalonia.Controls.DataGrid自动合并列

娥搽裙 2026-2-10 18:50:00
Winform在用的DataGridView修改为通过线条和透明的方式实现了合并列的效果。一段时间也在留意Avalonia.Controls.DataGrid是否也有类似的做法。一直没有心思去看那些代码,水平有限,实在搞不懂XML/Content一类如何实现绘制内容的。借着AI的帮助终于能试着去修改了。
让AI从DataGrid的以下方法入手
  1.         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方法,于是将合并的代码主要放在其中
  1. internal void EnsureGridLine(DataGridColumn lastVisibleColumn){    if (OwningGrid != null && _rightGridLine != null)    {        if (OwningGrid.VerticalGridLinesBrush != null && OwningGrid.VerticalGridLinesBrush != _rightGridLine.Fill)        {            _rightGridLine.Fill = OwningGrid.VerticalGridLinesBrush;        }        //忽略其他代码
  2.         // 调用DataGrid的CheckCellToMerge方法    var (isSameAsPrevious, isSameAsNext) = OwningGrid?.CheckCellToMerge(this) ?? (false, false);        // 根据不同的组合情况处理底边框和透明度    HandleMergeResult(isSameAsPrevious, isSameAsNext);}
复制代码
至此,DataGrid决定如何合并,返回当前行与上一行和下一行的数据是否可以合并(现在只是简单的比较当前列的内容是否一致)。

有一个小小的问题,在滚动时合并列可能会显示空白。虽说在用的winform版的datagridview也有这个小问题。但新的东西多少有点改进,对吧。于是我向AI发出要求。最大的帮助就是判断是否是当前显示的第一列的方法了。
  1. /// /// 判断指定行是否为可视区域的第一行/// /// 要检查的行/// 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发起,看以下方法
  1. 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[lastVisibleColumn.Index];        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
 

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

相关推荐

您需要登录后才可以回帖 登录 | 立即注册