WPF DataGrid滚动时行头自定义箭头重复显示问题
问题根因
WPF DataGrid默认开启UI虚拟化机制,当数据量超出可视区域生成垂直滚动条时,DataGrid不会为全量数据创建持久化的DataGridRow行容器,仅维护可视区域范围内的行实例,滚动过程中会反复复用这些行容器渲染不同索引的数据。
你当前的实现直接为GetRow方法返回的单个行容器实例设置箭头Header,当这个行容器被滚动事件触发复用来渲染其他行数据时,之前设置的箭头不会被自动清除,最终出现箭头每隔数行重复显示的现象,和行定位方法的效率无关。
修复方案
不要直接操作单次获取的行容器实例,改为在DataGrid.LoadingRow事件中动态判断行索引、设置Header,确保行容器复用时非起始行的Header会被主动清空,避免样式残留。
- 新增类级别属性存储当前导入起始行索引,调整起始点时同步更新该属性即可
- 为DataGrid注册
LoadingRow事件,每次行容器加载/复用时根据当前行的真实索引判断是否显示箭头 - 移除原有直接给行实例设置Header的逻辑,更新起始行后调用
Items.Refresh()触发行重新加载即可
修正后的代码
起始行属性定义
' 替换原有SetStartingRowArrowHeader里的临时startingRow变量 Private _currentStartImportRow As Integer Public Property CurrentStartImportRow As Integer Get Return _currentStartImportRow End Get Set(value As Integer) _currentStartImportRow = value ' 刷新列表触发行重新加载,更新箭头显示 dgExcelDataGrid.Items.Refresh() RaiseCanShiftStartingRowCommandChanged() End Set End Property
DataGrid行加载事件(在窗口初始化/导入Excel前注册一次即可)
' 注册事件,不要重复注册 AddHandler dgExcelDataGrid.LoadingRow, AddressOf DgExcelDataGrid_LoadingRow Private Sub DgExcelDataGrid_LoadingRow(sender As Object, e As DataGridRowEventArgs) Dim currentRow As DataGridRow = e.Row ' 获取当前行容器绑定的真实数据索引,虚拟化场景下不要用行容器自带的GetIndex方法,会出现索引不准的问题 Dim realRowIndex As Integer = dgExcelDataGrid.Items.IndexOf(currentRow.Item) If realRowIndex = CurrentStartImportRow Then Dim arrowIcon = New FontAwesome.WPF.ImageAwesome() arrowIcon.Icon = FontAwesome.WPF.FontAwesomeIcon.ArrowCircleOutlineRight arrowIcon.Width = 15 arrowIcon.Height = 15 arrowIcon.Foreground = Brushes.Blue currentRow.Header = arrowIcon Else ' 非起始行必须清空Header,避免容器复用导致箭头残留 currentRow.Header = Nothing End If End Sub
修正后的起始行设置方法
Private Sub SetStartingRowArrowHeader() Dim _window = TryCast(Me.NotifyWindow, Import) dgExcelDataGrid = _window.dgExcelDataGrid ' 仅更新起始行属性,自动触发列表刷新 CurrentStartImportRow = ExcelSheetTypeSelected.Start_Import_Row End Sub
补充说明
原有的GetRow扩展方法可以保留,其他需要临时操作可视行的场景仍可正常使用,仅不适合用来设置需要持久生效的行样式、行内容这类受虚拟化复用影响的属性。
内容的提问来源于stack exchange,提问作者Mohamad Hammash
相关产品推荐
相关产品推荐

