Ein DateGridView mit Drag and Drop der gesamten Zeile.
– Multiselect möglich (verschiebt alle markierten Zeilen)
– Behällt die selektieren Zeilen nach dem ablegen
– Zeigt einen visuellen Strich am Einfügepunkt ober oder unterhalb der Zeile
– Scrollt automatisch hoch/runter
//works with multiselect rows
//shows divider
//todo after dragover click on multiselect rows deselect it
private static int rowIndexFrom = -1;
private static int rowIndexTo = -1;
private static int[] dataGridViewSelectedRows = null;
private void dataGridView1_Paint(object sender, PaintEventArgs e)
{
if (rowIndexTo == -1) return;
var dataGridView = sender as DataGridView;
var rect = dataGridView1.GetRowDisplayRectangle(rowIndexTo, false);
int posY = (rowIndexTo > rowIndexFrom && !dataGridView.Rows[rowIndexTo].IsNewRow)
? rect.Bottom : rect.Top;
using (var pen = new Pen(Color.FromArgb(150, 33, 186, 71), 7))
e.Graphics.DrawLine(pen, new Point(rect.Left, posY - 1), new Point(rect.Right, posY - 1));
}
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) != MouseButtons.Left) { rowIndexTo = -1; return; }
var dataGridView = sender as DataGridView;
if (!dataGridView1.AllowDrop || dataGridView.ReadOnly || dataGridView.SelectedRows.Count == 0) { rowIndexTo = -1; return; }
var hitTestInfo = dataGridView.HitTest(e.X, e.Y);
if (hitTestInfo.ColumnIndex == -1)
{
}
foreach (DataGridViewRow row in dataGridView.SelectedRows)
if (row.IsNewRow) row.Selected = false;
dataGridViewSelectedRows = dataGridView.SelectedRows.Cast().Select(row => row.Index).ToArray();
if (dataGridView1.SelectedRows.Count == 0) { rowIndexFrom = -1; return; }
rowIndexFrom = hitTestInfo.RowIndex;
if (dataGridViewSelectedRows.Contains(rowIndexFrom))
{
dataGridView.EndEdit();
Task.Factory.StartNew(() =>
{
dataGridView.Invoke(new Action(() =>
{
if (dataGridViewSelectedRows?.Length > 1)
foreach (int row in dataGridViewSelectedRows) dataGridView.Rows[row].Selected = true;
if (rowIndexFrom != -1 && dataGridView.Rows.Count >= dataGridViewSelectedRows?.Length)
dataGridView.DoDragDrop(0, DragDropEffects.Move);
}));
});
}
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
if (rowIndexFrom == -1) return;
var dataGridView = sender as DataGridView;
if (!dataGridView.AllowDrop || dataGridView.ReadOnly || dataGridView.SelectedRows.Count <= 0) { rowIndexTo = -1; return; }
e.Effect = DragDropEffects.Move;
try
{
Point clientPointer = dataGridView.PointToClient(new Point(e.X, e.Y));
rowIndexTo = dataGridView.HitTest(clientPointer.X, clientPointer.Y).RowIndex;
if (dataGridView.Rows[rowIndexTo].IsNewRow) { rowIndexTo--; }
}
catch
{
rowIndexTo = -1;
}
if (dataGridViewSelectedRows?.Length > 1 && dataGridViewSelectedRows.Contains(rowIndexTo) && dataGridViewSelectedRows.Contains(rowIndexTo - 1))
{
rowIndexTo = -1;
}
#region Scrollen beim Verschieben von Zeilen
Point clientPoint = dataGridView.PointToClient(new Point(e.X, e.Y));
//Converts window position to user control position (otherwise you can use MousePosition.Y)
int mousepos = PointToClient(Cursor.Position).Y;
//If the mouse is hovering over the bottom 5% of the grid
if (mousepos > (dataGridView1.Location.Y + (dataGridView1.Height * 0.95)))
{
mouseMoveDown = true;
//If the first row displayed isn't the last row in the grid
if (dataGridView1.FirstDisplayedScrollingRowIndex < dataGridView1.RowCount - 1)
{
//Increase the first row displayed index by 1 (scroll down 1 row)
int firstDisplRow = dataGridView1.FirstDisplayedScrollingRowIndex;
if (dataGridView1.Rows[firstDisplRow + 1].Displayed)
{
Thread.Sleep(60);
dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.FirstDisplayedScrollingRowIndex + 1;
}
}
}
//If the mouse is hovering over the top 5% of the grid
if (mousepos < (dataGridView1.Location.Y + (dataGridView1.Height * 0.55)))
{
mouseMoveDown = false;
//If the first row displayed isn't the first row in the grid
if (dataGridView1.FirstDisplayedScrollingRowIndex > 1)
{
int firstDisplRow = dataGridView1.FirstDisplayedScrollingRowIndex;
Thread.Sleep(60);
dataGridView1.FirstDisplayedScrollingRowIndex -= 1;
}
}
#endregion
dataGridView.Refresh();
}
private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
if (rowIndexTo == -1) return;
var dataGridView = sender as DataGridView;
if (!dataGridView.AllowDrop || dataGridView.ReadOnly || dataGridView.SelectedRows.Count <= 0) { rowIndexTo = -1; dataGridView.Refresh(); return; }
if (rowIndexTo == rowIndexFrom && dataGridView.SelectedRows.Count == 1) { rowIndexTo = -1; dataGridView.Refresh(); return; }
if (rowIndexTo == -1) { dataGridView.Refresh(); return; }
if (e.Effect == DragDropEffects.Move)
{
dataGridView.Invoke(new Action(() =>
{
List rowsToMove = dataGridView.SelectedRows.Cast().OrderBy(row => row.Index).ToList();
bool indexInbetweenRows = rowIndexTo > rowsToMove.Min(row => row.Index) && rowIndexTo < rowsToMove.Max(row => row.Index);
if (indexInbetweenRows) rowIndexTo = rowsToMove.Min(row => row.Index);
rowIndexTo = rowIndexFrom >= rowIndexTo ? rowIndexTo : rowIndexTo - (rowsToMove.Count - 1);
foreach (DataGridViewRow row in rowsToMove) dataGridView.Rows.Remove(row);
int insertIndex = rowIndexTo;
rowsToMove.ForEach(row => dataGridView.Rows.Insert(insertIndex++, row));
dataGridView.ClearSelection();
dataGridView.CurrentCell = dataGridView.Rows[rowIndexTo].Cells[dataGridView.FirstDisplayedCell.ColumnIndex];
rowsToMove.ForEach(row => row.Selected = true);
}));
}
rowIndexTo = -1;
dataGridView.Refresh();
}
private void dataGridView1_MouseLeave(object sender, EventArgs e)
{
rowIndexTo = -1;
dataGridView1.Refresh();
}

