Question Dragging multiple rows from one datagridview to another

nyarlathotep

Member
Joined
Mar 23, 2012
Messages
6
Programming Experience
1-3
After much googling I've put together an 'almost' solution to dragging and dropping multiple rows from one grid to another. This is going to be a long post.:crying:

It's basically code borrowed and modified from two different webpages.

There is a class which modifies the datagridview control to create a new control I'm calling multigrid. The code is in block 1 below.
I think this line from 'Overrides OnMouseMove'
VB.NET:
Dim dropEffect As DragDropEffects = Me.DoDragDrop(Me.SelectedRows, DragDropEffects.Move)

Should put the SelectedRows object into the drag data.

If make a form then add this control as multiselect1 and a datagridview as datagridview2 (with the same column settings). I think I should be able to select a bunch of rows in multiselect1 and drop them onto datagridview2 by coding as in code block 2.

Problem: It doesn't build with the Error 'Expression is of type 'System.Windows.Forms.IDataObject', which is not a collection type. Obviously the .selectedrows is a collection so clearly the compiler isn't seeing that.

Can Obi Wan help. You're my only hope.

Code Block One 'multiselect class'
VB.NET:
Imports System.DrawingImports System.IO
Imports System.ComponentModel
Imports System.Reflection
Imports System.Windows.Forms


<ToolboxBitmap(GetType(multigrid), "multigridicon.bmp")>
Public Class multigrid


    Inherits System.Windows.Forms.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

Code block 2 'drag drop handling'
VB.NET:
 Private Sub DataGridView2_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView2.DragOver        'Just to Show a mouse icon to denote drop is allowed here
        e.Effect = DragDropEffects.Move
    End Sub


    Private Sub DataGridView2_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView2.DragDrop
        Dim oRow As DataGridViewRow
        Dim oRow2 As DataGridViewRow
        Try


            For Each oRow In e.Data


                oDataRow = DataGridView2.NewRow
                CopyDataRow(oSourceDataRow, oDataRow)


            Next oRow


        Catch ex As Exception
            MsgBox(ex.Message)
        End Try


    End Sub


    Private Sub CopyDataRow(ByVal oSourceRow As DataRow, ByVal oTargetRow As DataRow)


        Dim nIndex As Integer = 0
        Dim oItem As Object


        '- Copy all the fields from the source row to the target row


        For Each oItem In oSourceRow.ItemArray


            oTargetRow(nIndex) = oItem
            nIndex += 1


        Next


    End Sub
 
In the DragDrop event handler, e.Data is NOT the data that you dragged. It is an object that provides access to the data that you dragged in potentially various forms. It provides methods to determine what forms the data is available in and to get the data in one of those forms. You should check this out:

Drag & Drop in Windows Forms

All examples are relevant from the point of view of using e.Data but there are a couple of examples in posts #22 and #23 that involve the DataGridView control that may be of particular interest.
 
In the DragDrop event handler, e.Data is NOT the data that you dragged. It is an object that provides access to the data that you dragged in potentially various forms. It provides methods to determine what forms the data is available in and to get the data in one of those forms. You should check this out:


Drag & Drop in Windows Forms


All examples are relevant from the point of view of using e.Data but there are a couple of examples in posts #22 and #23 that involve the DataGridView control that may be of particular interest.


Thanks for the steer I didn't find that thread when browsing earlier. I used the 'building from basics' section (#3) to understand better what e.Data was and how to read it


So I came up with this. Can you suggest any improvements? Such as getting rid of any unnecessary bits of the code, making it more error tolerant or pulling the whole 'check is a columns is there, write a value into it' into a function.


VB.NET:
    Private Sub DataGridView2_DragDrop(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView2.DragDrop


        Dim index As Integer
        Dim Dr As DataRow


        Try
            'work thought the formats of e.Data
            For Each format As String In e.Data.GetFormats()


                'for each format walk through the rows objects within
                For Each oRow As DataGridViewRow In e.Data.GetData(format)


		    'Get the Index value for each row in the collection we have recieved
                    index = oRow.Index


                    'create a new row for this data
                    Dr = DT2.NewRow
                    
                    'Write into the new row the relvant data where the column names match up.
                    For i = 0 To Multigrid1.Columns.Count - 1


                        If DataGridView2.Columns.Contains(Multigrid1.Columns(i).Name) Then


                            Dr(Multigrid1.Columns(i).Name) = Multigrid1.Rows(index).Cells(i).Value.ToString()


                        End If


                    Next i


                    DT2.Rows.Add(Dr)


                Next oRow


            Next format


        Catch ex As Exception


            MsgBox(ex.Message)


        End Try


    End Sub
 
Back
Top