如何在我的WinForms应用程序中设置数据网格滚动条的位置?

29
在我的 C# WinForms 应用程序中,我有一个数据网格。当数据网格重新加载时,我想将滚动条设置回用户上一次的位置。我该如何做?
编辑:我使用的是旧的 WinForms DataGrid 控件,而不是较新的 DataGridView 控件。
7个回答

42

实际上,你并不直接与滚动条交互,而是设置FirstDisplayedScrollingRowIndex。因此在重新加载之前,捕获该索引,一旦重新加载完成,将其重置为该索引。

编辑:评论中提出了一个很好的观点。如果你正在使用DataGridView,那么这将起作用。如果你正在使用旧的DataGrid,那么最简单的方法是从它继承。请参见:链接

DataGrid有一个受保护的GridVScrolled方法,可用于将网格滚动到特定行。要使用它,请从DataGrid派生一个新网格并添加一个ScrollToRow方法。

C#代码:

public void ScrollToRow(int theRow)
{
    //
    // Expose the protected GridVScrolled method allowing you
    // to programmatically scroll the grid to a particular row.
    //
    if (DataSource != null)
    {
        GridVScrolled(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, theRow));
    }
}

我正在使用旧的DataGrid控件。 - ScottG
我仍在使用旧的DataGrid :),链接回答得非常好。但我担心这个链接不会持续太久,因为它已经超过4年了,我在这里重新发布答案以供将来参考。 - Bravo
需要知道第一个可见的“DataGrid”行的索引的人:请参阅我下面的帖子。 - Pollitzer

13

没错,一定是FirstDisplayedScrollingRowIndex。在某些用户交互后,您需要捕获此值,然后在重新加载网格后,您将希望将其设置回旧值。

例如,如果重新加载是由按钮点击触发的,则在按钮点击处理程序中,您可能希望将此值作为第一行命令放入变量中:

// Get current user scroll position
int scrollPosition = myGridView.FirstDisplayedScrollingRowIndex;

// Do some work
...

// Rebind the grid and reset scrolling
myGridView.DataBind;
myGridView.FirstDisplayedScrollingRowIndex = scrollPosition;

3

将垂直和水平滚动值存储到某个变量中并重置它们。

int v= dataGridView1.VerticalScrollingOffset ;
int h= dataGridView1.HorizontalScrollingOffset ;
//...reload
dataGridView1.VerticalScrollingOffset = v;
dataGridView1.HorizontalScrollingOffset =h; 

4
HorizontalScrollingOffset和VerticalScrollingOffset没有设置器。 - Shahin
仍然可以工作(.NET 4.5.1) - Mario The Spoon
2
VerticalScrollingOffset是只读的(VB.NET 4.5.2),但我只需要HorizontalScrollingOffset,这个完美地解决了我的问题。 - SteveCinq

3
您可以使用以下代码保存滚动位置。
int Scroll;
void DataGridView1Scroll(object sender, ScrollEventArgs e)
    {
        Scroll = dataGridView1.VerticalScrollingOffset;
    }

在刷新、加载dgv之后,您可以使用以下代码将dgv的滚动设置为相同的位置:

PropertyInfo verticalOffset = dataGridView1.GetType().GetProperty("VerticalOffset", BindingFlags.NonPublic | 
BindingFlags.Instance);
verticalOffset.SetValue(this.dataGridView1, Scroll, null); 

1
所有的User32.dll相关内容都无法与DataGridView一起使用,但是您的属性魔法起作用了,谢谢。这应该是被接受的答案。 - nivs1978

1

刚刚在BFree提供的链接中发布了答案。

DataGrid有一个受保护的GridVScrolled方法,可以用于将网格滚动到特定行。要使用它,请从DataGrid派生一个新网格,并添加一个ScrollToRow方法。

C#代码

public void ScrollToRow(int theRow)
{
    //
    // Expose the protected GridVScrolled method allowing you
    // to programmatically scroll the grid to a particular row.
    //
    if (DataSource != null)
    {
        GridVScrolled(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, theRow));
    }
}

VB.NET 代码

Public Sub ScrollToRow(ByVal theRow As Integer)
    '
    ' Expose the protected GridVScrolled method allowing you
    ' to programmatically scroll the grid to a particular row.
    '
    On Error Resume Next

    If Not DataSource Is Nothing Then
        GridVScrolled(Me, New ScrollEventArgs(ScrollEventType.LargeIncrement, theRow))
    End If
End Sub

0
尽管这是一个老问题,但上面的很多解决方案对我来说都不起作用。最终起作用的是:
if(gridEmployees.FirstDisplayedScrollingRowIndex != -1) gridEmployees.FirstDisplayedScrollingRowIndex = 0;

0

我使用了@BFree的答案,但还需要捕获DataGrid中的第一行可见行:

int indexOfTopMostRow = HitTest(dataGrid.RowHeaderWidth + 10, 
                                dataGrid.PreferredRowHeight + 10).Row;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接