Search code examples
c#datagridviewscrollbarpanel

C#: Scroll 2 Controls with 1 ScrollBar


I have a DataGridView control and a Panel control placed next to each other with the same height, and both of them have a vertical scrollbar scrollable to the same distance. What I want to achieve is, I control the scrollbar on the DataGridView and move the scrollbar of the Panel the same degree each time.

I found some examples where both controls are DataGridView's but in my case, one is a Panel. I tried the following:

//Inside a for loop
myDGV[i].Scroll += (sender, e) => {
    if(e.ScrollOrientation == ScrollOrientation.VerticalScroll)
    {
        int val = myDGV[i].FirstDisplayedScrollingRowIndex; //Error on this line
        myPanel[i].VerticalScroll.Value = val;
    }
};

but it gives an error:

IndexOutOfRangeException was unhandled.
Index was outside the bounds of the array.

I also found Using one scroll bar to control two DataGridView and tried the following:

//This is also inside a for loop
myDGV[i].Scroll += (sender, e) => {
    myPanel[i].VerticallScrollBar.Value = e.NewValue;
};

but it gave me the same error. I have 4 instances of each (DataGridView and Panel, and each i corresponds to each other's. Panel's are declared correctly, but I am not sure why I am getting this error.

Can anyone help please?


Solution

  • You should be getting a warning in your code regarding "Access to modified closure" on your use of variable i inside the delegates.

    What is happening is your delegate is using the local variable i, which will most likely have changed it's value before the event is raised (probably 1 more than your array length). Also, all events will be using exactly the same value of i.

    The answer is to create a new integer variable INSIDE the for loop, initialised to the current value of i. Make sure you do not modify this integer after you have added the delegate. All data grid views will be using their own copies of the variable which will have the correct value.

    Try something like the following as a solution :

    for (int i = 0; i < myDGV.Length; i++)
    {
        int ii = i;
    
        myDGV[i].Scroll += (sender, e) => {
            if(e.ScrollOrientation == ScrollOrientation.VerticalScroll)
            {
                int val = myDGV[ii].FirstDisplayedScrollingRowIndex;
                myPanel[ii].VerticalScroll.Value = val;
            }
        };
    }