Drag and Drop Rows of Datagrid View Winform C#

2020-07-30 03:14发布

问题:

I want to Drag Rows from certain position to another position in same grid view. The Other rows should automatically adjust according to the Drag and Drop.

Thank You

回答1:

I much prefer using mouse events over actual drag&drop events for this when doing d&d within an application.

1 - Unbound example

Here is a simple example that uses the mouse events to drag rows around while diplaying one Cell value in a Label.

It inserts the row after the one you drop it on.

The dragLabel part is optional..

First we declare two helper variables at class level:

int dragRow = -1;
Label dragLabel = null;

Then we code the CellMouseDown to prepare the Label..:

private void dataGridView1_CellMouseDown(object sender,DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex<0 || e.RowIndex < 0) return;
    dragRow = e.RowIndex;
    if (dragLabel == null) dragLabel = new Label();
    dragLabel.Text = dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();
    dragLabel.Parent = dataGridView1;
    dragLabel.Location = e.Location;
}

In the MouseMove we just move the Label. But as the MouseDown usually starts a cell selection we clear the selection..

private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left && dragLabel != null)
    {
        dragLabel.Location = e.Location;
        dataGridView1.ClearSelection();
    }
}

The real work is in the MouseUp. We need a HitTest to find out which, if any, row we are on. We also need to calculate the target row depending on the direction of the drag.

Finally we clean up the Label..

private void dataGridView1_MouseUp(object sender, MouseEventArgs e)
{
    var hit = dataGridView1.HitTest(e.X,e.Y);
    int dropRow = -1;
    if (hit.Type != DataGridViewHitTestType.None)
    {
        dropRow =   hit.RowIndex;
        if (dragRow >= 0 )
        {
            int tgtRow = dropRow + (dragRow > dropRow ? 1 : 0);
            if (tgtRow != dragRow)
            {
                DataGridViewRow row = dataGridView1.Rows[dragRow];
                dataGridView1.Rows.Remove(row);
                dataGridView1.Rows.Insert(tgtRow, row);

                dataGridView1.ClearSelection();
                row.Selected = true;
            }
        }
    }
    else  { dataGridView1.Rows[dragRow].Selected = true;}

    if (dragLabel != null)
    {
        dragLabel.Dispose();
        dragLabel = null;
    }
}

A few notes:

Make sure no row is new or modified or you can't move it. It took me awhile to realize that I had to switch off AllowUserToAddRows before adding the rows initially..

The treatment of selections is up to you. I chose to select the dragged row if the drop fails. And I chose to let it fail when dragging into the empty space.

Update:

2 - DataBound example

If the DGV is data-bound you can't move the rows directly. Instead you need to move the rows in the DataSource.

Let's assume you have a DataTable DT. Then you can remove rows from it and insert rows at any position. (Quite different from SQL DBMS tables!)

Note that a DataRow loses its values once removed from the DataTable. Therefore we need to clone the values before we remove the row. Other than that the code is pretty much the same. Simply replace the innermost condition with this:

if (tgtRow != dragRow)
{
    DataRow dtRow = DT.Rows[dragRow];
    DataRow newRow = DT.NewRow();
    newRow.ItemArray = DT.Rows[dragRow].ItemArray; // we need to clone the values

    DT.Rows.Remove(dtRow);
    DT.Rows.InsertAt(newRow, tgtRow);
    dataGridView1.Refresh();
    dataGridView1.Rows[tgtRow].Selected = true;
}