Tip: Auto Scroll While Implementing Drag & Drop for Reordering Rows in DataGridView

There are tons of articles detailing how to re-order rows in a data grid (here is a good one) but none handle this nuance of allowing the user to scroll up and down while dragging a row to a point beyond the displayed rows on the screen.

The Problem

Say a form hosts a datagrid that was sized to display 10 rows, and the gridvew has 100 rows. If the user has scrolled down to a point where the gridview displays rows 30 to 40, and if the user wants to move the 35th row to the second position, the gridview by default doesn’t scroll up when user drags row 25 beyond the row header (or beyond row 40). This can be very annoying.

The Solution

This solution, in just four lines of code, implements the scroll up and scroll down feature when user drags a row beyond the datagridview’s top and bottom bounds. After implementing the code to do a drag and drop re-ordering, in the DragOver event handler, add the following lines (the code assumes you have a datagridvew object called dataGridView1.)

private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
   e.Effect = DragDropEffects.Move;

   if (e.Y <= PointToScreen(new Point(dataGridView1.Location.X,
      dataGridView1.Location.Y)).Y+40)
      dataGridView1.FirstDisplayedScrollingRowIndex -= 1;
   if (e.Y >= PointToScreen(new Point(dataGridView1.Location.X+
      dataGridView1.Width, dataGridView1.Location.Y+
      dataGridView1.Height)).Y - 10)
   dataGridView1.FirstDisplayedScrollingRowIndex += 1;
}

Code Explained

Initially, I tried to handle this in the mouse move event when the LButton was down and the row index returned was equal to the datagridvew’s FirstDisplayedScrollingRowIndex. But, this didn’t work; when I used Debug.Write to trace the problem (because placing a break point in mouse move is next worst thing to HELL), I noticed that the move events were not fired when the LButton was down and after the cursor has moved out of the selected row (I assume that the do drag was eating away these events).

So, I changed my focus to the DragOver event handler. The code is pretty straightforward; it uses the following condition to check whether the user is dragging beyond the top visible row.

if (e.Y <= PointToScreen(new Point(dataGridView1.Location.X,
   dataGridView1.Location.Y)).Y+40)

Note: The PointToScreen conversion as dataGridView1.Location.X will give co-ordinates relative to the hosted form and e.Y gives co-ordinates relative to the screen.

I am adding an offset of 40 just to accommodate for the header size (someone can probably write bettor code by calculating the header hight). Once the condition is satisfied, just call the code to increment or decrement the datagridview’s FirstDisplayedScrollingRowIndex.

Happy coding.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read