33

I've DataGridView that bound a List<myClass> and i sort it by "Priority" property in "myClass". So I want to drag an "DataGridViewRow" to certain position to change it's "Priority" property.

How could I "Drag & Drop" DataGridView Rows ?. And how to handle this ?.

Wahid Bitar
  • 13,776
  • 13
  • 78
  • 106

2 Answers2

63

I found this code sample on MSDN

Note the following:

1). DataGridView property AllowDrop must be set to true (default is false).

2). The example below works out of the box when the DataGridView is NOT data-bound. Otherwise it will throw an InvalidOperationException. If it is databound, you should manipulate the order of items in the DataSource.

private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
    if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
    {
        // If the mouse moves outside the rectangle, start the drag.
        if (dragBoxFromMouseDown != Rectangle.Empty &&
            !dragBoxFromMouseDown.Contains(e.X, e.Y))
        {

            // Proceed with the drag and drop, passing in the list item.                    
            DragDropEffects dropEffect = dataGridView1.DoDragDrop(
            dataGridView1.Rows[rowIndexFromMouseDown],
            DragDropEffects.Move);
        }
    }
}

private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
    // Get the index of the item the mouse is below.
    rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
    {
        // Remember the point where the mouse down occurred. 
     // The DragSize indicates the size that the mouse can move 
     // before a drag event should be started.                
        Size dragSize = SystemInformation.DragSize;

        // Create a rectangle using the DragSize, with the mouse position being
        // at the center of the rectangle.
        dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                                                       e.Y - (dragSize.Height / 2)),
                            dragSize);
    }
    else
        // Reset the rectangle if the mouse is not over an item in the ListBox.
        dragBoxFromMouseDown = Rectangle.Empty;
}

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

private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
    // The mouse locations are relative to the screen, so they must be 
    // converted to client coordinates.
    Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));

    // Get the row index of the item the mouse is below. 
    rowIndexOfItemUnderMouseToDrop =
        dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;

    // If the drag operation was a move then remove and insert the row.
    if (e.Effect== DragDropEffects.Move)
    {
        DataGridViewRow rowToMove = e.Data.GetData(
            typeof(DataGridViewRow)) as DataGridViewRow;
        dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
        dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);

    }
}
Mike de Klerk
  • 11,906
  • 8
  • 54
  • 76
Wahid Bitar
  • 13,776
  • 13
  • 78
  • 106
  • A link to the original article would be appreciated :) Thanks – Teejay Oct 22 '12 at 08:05
  • Actually it's from two years ago and I think it's from here : http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/16b0a44e-35a0-4bc8-9ccd-ec2c62c95a55 – Wahid Bitar Oct 22 '12 at 17:46
  • 4
    One small issue with this otherwise great code snippet: if your DGV allows adding rows, and you drag a row all the way to the end, it'll remove the row, then try to insert it past the "dummy" row, which isn't allowed, with the end result that the dropped row will be deleted (clearly not what you want). Have to check for that: this.uxSigningParties.Rows.RemoveAt(rowIndexFromMouseDown); if (rowIndexOfItemUnderMouseToDrop >= this.uxSigningParties.Rows.Count) { rowIndexOfItemUnderMouseToDrop--; } – neminem Feb 03 '16 at 18:04
  • idk why I am having such a issue with this code, but it seems no matter where I drop it it deletes the last entry. – Shadowblitz16 May 21 '19 at 19:18
3

The Answer from 'Wahid Bitar' helped me a lot. I cannot comment the above, so a small addition: If deleting a row is unwanted as commented by 'neminem': Just add to DragDrop Event just before the lines that finally moves it:

        if (rowIndexOfItemUnderMouseToDrop < 0 )
        {
            return;
        }        
       dataGridView1.Rows.RemoveAt(rowIndexFromMouseDown);
       dataGridView1.Rows.Insert(rowIndexOfItemUnderMouseToDrop, rowToMove);
Wilhelm
  • 196
  • 10