我有一个窗体上有两个 DataGridView 控件的应用程序。网格彼此相邻排列,两者都处于虚拟模式,并且行需要保持对齐。其中一个网格位于控件中,该控件公开 FirstDisplayedScrollingRowIndex 属性和滚动事件。
当任一网格滚动时,其他网格的 FirstDisplayedScrollingRowIndex 属性将设置为保持对齐。
DoubleBuffer 已使用以下方法设置为 true:
dataGridViewLines.GetType.InvokeMember("DoubleBuffered", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.SetProperty, Nothing, dgvStoreLines, New Object() {True})
该应用程序最初是用 VS2005 编写的,并已在 VB 中升级到 vs2012,但很高兴在 C# 中得到答案。
当任一控件设置其他控件的 FirstDisplayedScrollingRowIndex 属性时,将设置一个标志以确保不会将第二个控件滚动事件引发回导致循环事件的容器。
第一个网格大约有 50 列,第二个网格有 8-10 个。网格中通常有大约 250-350 行数据。
问题是,当使用鼠标滚轮滚动其中一个网格时,即使滚动条完全对齐,在第二个网格中的数据与第一个网格对齐之前,您也会有一点延迟。如果你用鼠标抓住滚动条向上或向下移动,另一个网格上的滚动条会完美移动,但网格数据在滚动条释放之前不会改变。
如果删除使它们保持对齐的代码,则每个网格都会按预期单独滚动。
CellValueNeeded 过程中有一些 case 语句,出于性能原因,这些语句已分解为小的 select 语句。
我尝试了以下代码:
dgv.SuspendLayout()
dgv.Refresh() ' have also tried dgv.PerformLayout()
dgv.ResumeLayout()
目前,以下粗略代码似乎提供了比 Refresh 或 PerformLayout 更好的结果。
For i As Integer = 0 To dgv.ColumnCount - 1
If dgv.Columns(i).Visible AndAlso dgv.Columns(i).Displayed Then
dgv.InvalidateColumn(i)
End If
Next
以下代码将错误重现到一定程度 - 这试图显示正在设置的大多数属性 - 我不允许发布任何实际代码。为了创建应用程序,我已添加到 datagridview 控件并将它们锚定到表单边缘。第二个网格添加了一个 DataGridViewComboBoxColumn 列 - 没有属性更改,向列表 AF 添加了六个值。
Private IsSettingDataGridView1RowIndex As Boolean = False
Private IsSettingDataGridView2RowIndex As Boolean = False
Private ReadOnlyColour As System.Drawing.Color = Color.FromArgb(255, 255, 255, 192)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For grid1columns As Integer = 0 To 50
DataGridView1.Columns.Add("Column " + grid1columns.ToString, "Column " + grid1columns.ToString)
DataGridView1.Columns(grid1columns).AutoSizeMode = DataGridViewAutoSizeColumnMode.None
Next
For grid1columns As Integer = 0 To 10
DataGridView2.Columns.Add("Column " + grid1columns.ToString, "Column " + grid1columns.ToString)
DataGridView1.Columns(grid1columns).AutoSizeMode = DataGridViewAutoSizeColumnMode.None
Next
PrepGrid(DataGridView1)
PrepGrid(DataGridView2)
End Sub
Private Sub PrepGrid(dgv As DataGridView)
dgv.VirtualMode = True
dgv.RowCount = 300
dgv.AllowUserToAddRows = False
dgv.AllowUserToResizeRows = False
dgv.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.True
dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
dgv.DefaultCellStyle.WrapMode = DataGridViewTriState.False
dgv.EditMode = DataGridViewEditMode.EditOnKeystroke
dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing
dgv.ShowCellToolTips = False
dgv.StandardTab = True
dgv.RowHeadersVisible = False
dgv.ScrollBars = ScrollBars.Vertical
End Sub
Private Sub DataGridView1_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
e.Value = String.Format("val r{0} c{1}", e.RowIndex, e.ColumnIndex)
End Sub
Private Sub DataGridView2_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles DataGridView2.CellValueNeeded
If e.ColumnIndex > 0 Then e.Value = String.Format("val r{0} c{1}", e.RowIndex, e.ColumnIndex)
DataGridView2.Rows(e.RowIndex).Cells(e.ColumnIndex).ReadOnly = (e.ColumnIndex < 2)
If e.ColumnIndex < 2 Then DataGridView2.Rows(e.RowIndex).Cells(e.ColumnIndex).Style.BackColor = ReadOnlyColour
End Sub
Private Sub DataGridView1_Scroll(sender As Object, e As ScrollEventArgs) Handles DataGridView1.Scroll
If Not IsSettingDataGridView2RowIndex Then
IsSettingDataGridView2RowIndex = True
DataGridView2.FirstDisplayedScrollingRowIndex = DataGridView1.FirstDisplayedScrollingRowIndex
IsSettingDataGridView2RowIndex = False
End If
End Sub
Private Sub DataGridView2_Scroll(sender As Object, e As ScrollEventArgs) Handles DataGridView2.Scroll
If Not IsSettingDataGridView1RowIndex Then
IsSettingDataGridView1RowIndex = True
DataGridView1.FirstDisplayedScrollingRowIndex = DataGridView2.FirstDisplayedScrollingRowIndex
IsSettingDataGridView1RowIndex = False
End If
End Sub