Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Drag drop multiple selected rows of datagridview with left mouse button

5.00/5 (4 votes)
2 Mar 2012CPOL 56.2K  
Drag drop multiple selected rows of datagridview with left mouse button
If you have a multiselectable datagridview on your form, you most likely are looking for a method to process intuitive drag & drop of the selected rows to another control. But, as soon as you click onto a row (selected or not) with the mere left button any selection is gone immediately. One could think about a workaround by using the right mouse button, but again, that is not intuitive, since 99% of all dd operations are normally done by click and hold of the left button.

What to do? Of course: subclassing. I thought about it for awhile and detected the crucial point in the OnMouseDown event. Inside this event, the base class of the datagridview is doing the selection job. So we override this event and wait for the OnMouseUp event to determine, if a multiselect drag drop has been performed. In this case, we catch up the preceeding MouseDown event and everything works fine.

Since we still want the 'only one row' dd as well, I also implemented the property
AllowMultiRowDrag
.

Here is the trick:

VB.NET
Public Class DD_DataGridView
    Inherits DataGridView

    Public Property AllowMultiRowDrag As Boolean = False
    Private dragBoxFromMouseDown As Rectangle
    Private rowIndexFromMouseDown As Int32
    Private lastLeftMouseDownArgs As MouseEventArgs

    Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
        If (e.Button And Windows.Forms.MouseButtons.Left) = Windows.Forms.MouseButtons.Left Then
            rowIndexFromMouseDown = Me.HitTest(e.X, e.Y).RowIndex
            If rowIndexFromMouseDown <> -1 Then
                Dim dragSize As Size = SystemInformation.DragSize
                dragBoxFromMouseDown = New Rectangle(New Point(e.X - (dragSize.Width / 2), e.Y - (dragSize.Height / 2)), dragSize)
                lastLeftMouseDownArgs = e 'remember the MouseEventArgs

                If AllowMultiRowDrag Then
                    Exit Sub 'Don't call the base function here to keep the selection
                End If

            Else
                dragBoxFromMouseDown = Rectangle.Empty
                lastLeftMouseDownArgs = Nothing
            End If
        End If
        MyBase.OnMouseDown(e) 'in all other cases call the base function
    End Sub

    Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
        If lastLeftMouseDownArgs IsNot Nothing AndAlso (e.Button And Windows.Forms.MouseButtons.Left) = Windows.Forms.MouseButtons.Left Then
            'there has been a multiselect drag operation so catch up the MouseDown event
            If AllowMultiRowDrag Then MyBase.OnMouseDown(lastLeftMouseDownArgs)
        End If
        MyBase.OnMouseUp(e)'now call the base Up-function
    End Sub
    Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
        If lastLeftMouseDownArgs IsNot Nothing AndAlso (e.Button And Windows.Forms.MouseButtons.Left) = Windows.Forms.MouseButtons.Left Then
            If (dragBoxFromMouseDown <> Rectangle.Empty) AndAlso (Not dragBoxFromMouseDown.Contains(e.X, e.Y)) Then
'we want to drag one/multiple rows
                Dim row As DataGridViewRow = Me.Rows(rowIndexFromMouseDown)
                row.Selected = True 'always select the row that was under the mouse in the OnMouseDown event.
                If Me.AllowMultiRowDrag Then
'multiselect drag, so make all selected rows the drag data
                    Dim dropEffect As DragDropEffects = Me.DoDragDrop(Me.SelectedRows, DragDropEffects.Move)
                Else
'only one row to drag
                    Dim dropEffect As DragDropEffects = Me.DoDragDrop(row, DragDropEffects.Move)
                End If
            End If
        End If
        MyBase.OnMouseMove(e) 'let's do the base class the rest
    End Sub
End Class

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)