0

我有一个窗体上有两个 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
4

1 回答 1

0

几个想法:

  1. 在应用程序的那部分运行分析器会很有趣。您是否有包含分析器的 VS 版本?听起来好像每次滚动动作都会发生很多事情,但我们不知道是什么——或者更准确地说,我们并不知道所有事情

  2. 您在程序中提到了一些听起来很复杂的case陈述CellValueNeeded。假设“过程”并不意味着“存储过程”,是否有可能在不重新架构整个事物的情况下缓存其中一些值?

ETA:我不知道您的示例代码在多大程度上代表了真实代码,但是您可以进行微小的性能调整:预先确定要更改的单元格,而不是每次都对Rowsand集合进行查找:Columns

DataGridViewCell cell = DataGridView2.Rows(e.RowIndex).Cells(e.ColumnIndex)
cell.ReadOnly = (e.ColumnIndex < 2)
If e.ColumnIndex < 2 Then cell.Style.BackColor = ReadOnlyColour
于 2013-07-11T15:21:05.183 回答