DGVs: Dragdrop copy + reorder with givefeedback

Ultrawhack

Well-known member
Joined
Jul 5, 2006
Messages
164
Location
Canada
Programming Experience
3-5
  • DGV1 is a databound DGV and DGV2 is unbound.
  • Both are Selectionmode=Fullrowselect, multiselect=false, AllowUserToAddRows=false
  • DGV1 rowselected can be dragdropped and copied to DGV2.
  • DGV2 rowselected should be reorderable within DGV2.
  • Both DGVs Givefeedback should use rowselected, column 1 as cursor.
1. With reference to JohnH's solution to dragdropping and copying items from databound DGV to unbound DGV2 in this thread

I am trying to take this a step further.

2. GiveFeedback on Dragdrop
I need to DGV1’s rowselected to givefeedback as items are being copied as per this thread. It seems logical that rowselected, column1 should be used as the cursor.

3. Reorder Rows on DGV2 with GiveFeedback
DGV2’s rows should be reorderable as per DGV FAQs. Also DGV2 should givefeedback on dragdrop reorder.

I am having real problems with getting all 3 modules to work together and I request help from the experts on this forum.

Thanks in advance.
 
Last edited:
What is correct selected row? What row do you want do be selected? There is sample code also inside to select a row, some like 'DGV1.Rows(rowix).Selected = True' Remember that you sometimes get rowix -1 when hittest returns header or Nowhere and have to make a decision about (a) not drop (b) append or (c) insert as first. In these cases you should also set selected row appropriately if you want the dropped row to be selected. But it could also be correct to leave the row previously selected when dragging from another control and dropping to say DGV2.
 
When DGV2's Row3 (apples) is dragged to Row1(bananas) then after the drop Row1 (apples) should be selected, right ? Not happening...

OK here's the DGV2 reorder code I'm testing with.
VB.NET:
[SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]If[/COLOR][/SIZE][SIZE=2] rowix <> -1 [/SIZE][SIZE=2][COLOR=#0000ff]Then
[/COLOR][/SIZE][SIZE=2]DGV2.Rows.Insert(rowix, rowToMove)
[/SIZE][SIZE=2][COLOR=#008000]'which row ?
[/COLOR][/SIZE][SIZE=2]MsgBox([/SIZE][SIZE=2][COLOR=#800000]"Reordered to row: "[/COLOR][/SIZE][SIZE=2] & rowix)
DGV2.Rows(rowix).Selected = [/SIZE][SIZE=2][COLOR=#0000ff]True[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#008000]' this row is not being selected
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]Else[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#008000]' append
[/COLOR][/SIZE][SIZE=2]DGV2.Rows.Add(rowToMove)
MsgBox([/SIZE][SIZE=2][COLOR=#800000]"Reordered to row: "[/COLOR][/SIZE][SIZE=2] & rowix)
DGV2.Rows(rowix).Selected = [/SIZE][SIZE=2][COLOR=#0000ff]True [COLOR=#008000]' this row is not being selected[/COLOR]
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]If
[/COLOR][/SIZE]
 
Surprising, one would think selecting a row would select it, but you're right it doesn't. I tried after the dodragdrop succeeded in mousedown too (just passing back the dropindex). Mouseup doesn't even trigger when dragdrop is initiated. Maybe it can't be done while the dragdrop operation occurs?
 
Thats strange. I can run a DGV1.Clearselection() from there and it works fine but DGV2 refuses to change or clear selection... still scratching my head on this one...
 
If some of sourceDGV's columns are hidden, this code will not copy the hidden column items to TargetDGV. How can I copy items from hidden columns to TargetDGV using this code ?
 
Can someone please help show me how to implement this solution found here to drag drop & reorder with target red-line feedback. How do I get this solution to work with an existing DGV on my form ?

http://www.danielsoper.com/programming/DataGridViewDragDropRowsColumns.aspx

VB.NET:
 Imports System
 Imports System.Collections.Generic
 Imports System.Text
 Imports System.Windows.Forms
 Imports System.Drawing

 Namespace MyDataGridView
     '''
     ''' This class extends the DataGridView to allow for custom
     ''' drag and drop reordering operations on both columns and rows.
     ''' The sequence of user interaction events occurs as follows:
     ''' 1. The user clicks (and releases) the left mouse button
     ''' on a row or column header cell to select the row or column.
     ''' 2. The user then clicks (and holds down) the left mouse
     ''' button to initiate a drag and drop operation which will allow
     ''' him/her to reorder the selected row or column within the
     ''' DataGridView.
     ''' 3. As the drag and drop operation begins, a horizontal (for
     ''' rows) or vertical (for columns) red line is displayed on the
     ''' DataGridView to indicate the target of the drag and drop operation
     ''' (i.e., to indicate where on the grid the selected row or column
     ''' will be dropped).
     ''' 4. When the user has selected the new target location for the
     ''' selected row/column, he/she releases the left mouse button, and
     ''' the appropriate reordering of columns or rows is carried out.
     ''' ******************************************************************
     ''' AUTHOR: Daniel S. Soper
     ''' URL: http://www.danielsoper.com
     ''' DATE: 02 February 2007
     ''' LICENSE: Public Domain. Enjoy! :-)
     ''' ******************************************************************
     '''
     Class MyDGV
         Inherits DataGridView
         'vars for custom column/row drag/drop operations
         Private DragDropRectangle As Rectangle
         Private DragDropSourceIndex As Integer
         Private DragDropTargetIndex As Integer
         Private DragDropCurrentIndex As Integer = -1
         Private DragDropType As Integer
         '0=column, 1=row
         Private DragDropColumn As DataGridViewColumn
         Private DragDropColumnCellValue As Object()
        
         Public Sub New()
             Me.AllowUserToResizeRows = False
             Me.SelectionMode = DataGridViewSelectionMode.CellSelect
             Me.AllowUserToOrderColumns = False
             Me.AllowDrop = True
             Me.ColumnCount = 20
             Me.RowCount = 40
             Me.Size = New Size(600, 400)
         End Sub
         'end default constructor
         Protected Overloads Overrides Sub OnColumnAdded(ByVal e As DataGridViewColumnEventArgs)
             'runs when a new column is added to the DGV
             e.Column.SortMode = DataGridViewColumnSortMode.Programmatic
             e.Column.HeaderText = "column " + e.Column.Index
             MyBase.OnColumnAdded(e)
         End Sub
         'end OnColumnAdded
         Protected Overloads Overrides Sub OnColumnHeaderMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
             'runs when the mouse is clicked over a column header cell
             If e.ColumnIndex > -1 Then
                 If e.Button = MouseButtons.Left Then
                     'single-click left mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.ColumnHeaderSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect
                         Me.Columns(e.ColumnIndex).Selected = True
                         'end if
                     End If
 ElseIf e.Button = MouseButtons.Right Then
                     'single-click right mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.ColumnHeaderSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect
                     End If
                     'end if
                     If Me.SelectedColumns.Count <= 1 Then
                         Me.ClearSelection()
                         Me.Columns(e.ColumnIndex).Selected = True
                         'show column right-click menu here
                         MessageBox.Show("show column right-click menu")
                     Else
                         'more than one column is selected
                         'show column right-click menu here
                         MessageBox.Show("show column right-click menu")
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnColumnHeaderMouseClick(e)
         End Sub
         'end OnColumnHeaderMouseClick
         Protected Overloads Overrides Sub OnRowHeaderMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
             'runs when the mouse is clicked over a row header cell
             If e.RowIndex > -1 Then
                 If e.Button = MouseButtons.Left Then
                     'single-click left mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.RowHeaderSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect
                         Me.Rows(e.RowIndex).Selected = True
                         Me.CurrentCell = Me(0, e.RowIndex)
                         'end if
                     End If
 ElseIf e.Button = MouseButtons.Right Then
                     'single-click right mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.RowHeaderSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect
                     End If
                     'end if
                     If Me.SelectedRows.Count <= 1 Then
                         Me.ClearSelection()
                         Me.Rows(e.RowIndex).Selected = True
                         Me.CurrentCell = Me(0, e.RowIndex)
                         'show row right-click menu here
                         MessageBox.Show("show row right-click menu")
                     Else
                         'more than one row is selected
                         'show row right-click menu here
                         MessageBox.Show("show row right-click menu")
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnRowHeaderMouseClick(e)
         End Sub
         'end OnRowHeaderMouseClick
         Protected Overloads Overrides Sub OnCellMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
             'runs when the mouse is clicked over a cell
             If e.RowIndex > -1 AndAlso e.ColumnIndex > -1 Then
                 If e.Button = MouseButtons.Left Then
                     'single-click left mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.CellSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.CellSelect
                         'end if
                     End If
 ElseIf e.Button = MouseButtons.Right Then
                     'single-click right mouse button
                     If Me.SelectionMode <> DataGridViewSelectionMode.CellSelect Then
                         Me.SelectionMode = DataGridViewSelectionMode.CellSelect
                     End If
                     'end if
                     If Me.SelectedCells.Count <= 1 Then
                         Me.ClearSelection()
                         Me(e.ColumnIndex, e.RowIndex).Selected = True
                         Me.CurrentCell = Me(e.ColumnIndex, e.RowIndex)
                         'show cell right-click menu here
                         MessageBox.Show("show cell right-click menu")
                     Else
                         'more than one cell is selected
                         'show cell right-click menu here
                         MessageBox.Show("show cell right-click menu")
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnCellMouseClick(e)
         End Sub
         'end OnCellMouseClick
         Protected Overloads Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
             'stores values for drag/drop operations if necessary
             If Me.AllowDrop Then
                 If Me.HitTest(e.X, e.Y).ColumnIndex = -1 AndAlso Me.HitTest(e.X, e.Y).RowIndex > -1 Then
                     'if this is a row header cell
                     If Me.Rows(Me.HitTest(e.X, e.Y).RowIndex).Selected Then
                         'if this row is selected
                         DragDropType = 1
                         Dim DragSize As Size = SystemInformation.DragSize
                         DragDropRectangle = New Rectangle(New Point(e.X - (DragSize.Width / 2), e.Y - (DragSize.Height / 2)), DragSize)
                         DragDropSourceIndex = Me.HitTest(e.X, e.Y).RowIndex
                     Else
                         DragDropRectangle = Rectangle.Empty
                         'end if
                     End If
 ElseIf Me.HitTest(e.X, e.Y).ColumnIndex > -1 AndAlso Me.HitTest(e.X, e.Y).RowIndex = -1 Then
                     'if this is a column header cell
                     If Me.Columns(Me.HitTest(e.X, e.Y).ColumnIndex).Selected Then
                         DragDropType = 0
                         DragDropSourceIndex = Me.HitTest(e.X, e.Y).ColumnIndex
                         Dim DragSize As Size = SystemInformation.DragSize
                         DragDropRectangle = New Rectangle(New Point(e.X - (DragSize.Width / 2), e.Y - (DragSize.Height / 2)), DragSize)
                     Else
                         DragDropRectangle = Rectangle.Empty
                         'end if
                     End If
                 Else
                     DragDropRectangle = Rectangle.Empty
                     'end if
                 End If
             Else
                 DragDropRectangle = Rectangle.Empty
             End If
             'end if
             MyBase.OnMouseDown(e)
         End Sub
         'end OnMouseDown
         Protected Overloads Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
             'handles drag/drop operations if necessary
             If Me.AllowDrop Then
                 If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
                     If DragDropRectangle <> Rectangle.Empty AndAlso Not DragDropRectangle.Contains(e.X, e.Y) Then
                         If DragDropType = 0 Then
                             'column drag/drop
                             Dim DropEffect As DragDropEffects = Me.DoDragDrop(Me.Columns(DragDropSourceIndex), DragDropEffects.Move)
 ElseIf DragDropType = 1 Then
                             'row drag/drop
                             Dim DropEffect As DragDropEffects = Me.DoDragDrop(Me.Rows(DragDropSourceIndex), DragDropEffects.Move)
                             'end if
                         End If
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnMouseMove(e)
         End Sub
         'end OnMouseMove
         Protected Overloads Overrides Sub OnDragOver(ByVal e As DragEventArgs)
             'runs while the drag/drop is in progress
             If Me.AllowDrop Then
                 e.Effect = DragDropEffects.Move
                 If DragDropType = 0 Then
                     'column drag/drop
                     Dim CurCol As Integer = Me.HitTest(Me.PointToClient(New Point(e.X, e.Y)).X, Me.PointToClient(New Point(e.X, e.Y)).Y).ColumnIndex
                     If DragDropCurrentIndex <> CurCol Then
                         DragDropCurrentIndex = CurCol
                             'repaint
                         Me.Invalidate()
                         'end if
                     End If
 ElseIf DragDropType = 1 Then
                     'row drag/drop
                     Dim CurRow As Integer = Me.HitTest(Me.PointToClient(New Point(e.X, e.Y)).X, Me.PointToClient(New Point(e.X, e.Y)).Y).RowIndex
                     If DragDropCurrentIndex <> CurRow Then
                         DragDropCurrentIndex = CurRow
                             'repaint
                         Me.Invalidate()
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnDragOver(e)
         End Sub
         'end OnDragOver
         Protected Overloads Overrides Sub OnDragDrop(ByVal drgevent As DragEventArgs)
             'runs after a drag/drop operation for column/row has completed
             If Me.AllowDrop Then
                 If drgevent.Effect = DragDropEffects.Move Then
                     Dim ClientPoint As Point = Me.PointToClient(New Point(drgevent.X, drgevent.Y))
                     If DragDropType = 0 Then
                         'if this is a column drag/drop operation
                         DragDropTargetIndex = Me.HitTest(ClientPoint.X, ClientPoint.Y).ColumnIndex
                         If DragDropTargetIndex > -1 AndAlso DragDropCurrentIndex < Me.ColumnCount - 1 Then
                             DragDropCurrentIndex = -1
                             'holds the appearance of the source column
                             DragDropColumn = Me.Columns(DragDropSourceIndex)
                             'holds the values of the cells in the source column
                             DragDropColumnCellValue = New Object(Me.RowCount - 2) {}
                             For i As Integer = 0 To Me.RowCount - 1
                                 'for each cell in the source column
                                 If Me.Rows(i).Cells(DragDropSourceIndex).Value IsNot Nothing Then
                                     'if this cell has a value, store it in the object array
                                     DragDropColumnCellValue(i) = Me.Rows(i).Cells(DragDropSourceIndex).Value
                                     'end if
                                 End If
                             Next
                             'next i
                             'remove the source column
                             Me.Columns.RemoveAt(DragDropSourceIndex)
                             'insert a new column at the target index using the source column as a template
                             Me.Columns.Insert(DragDropTargetIndex, New DataGridViewColumn(DragDropColumn.CellTemplate))
                             'copy the source column's header cell to the new column
                             Me.Columns(DragDropTargetIndex).HeaderCell = DragDropColumn.HeaderCell
                             'select the newly-inserted column
                             Me.Columns(DragDropTargetIndex).Selected = True
                             'update the position of the cuurent cell in the DGV
                             Me.CurrentCell = Me(DragDropTargetIndex, 0)
                             For i As Integer = 0 To Me.RowCount - 1
                                 'for each cell in the new column
                                 If DragDropColumnCellValue(i) IsNot Nothing Then
                                     'set the cell's value equal to that of the corresponding cell in the source column
                                     Me.Rows(i).Cells(DragDropTargetIndex).Value = DragDropColumnCellValue(i)
                                     'end if
                                 End If
                             Next
                             'next i
                             'release resources
                             DragDropColumnCellValue = Nothing
                             DragDropColumn = Nothing
                             'end if
                         End If
 ElseIf DragDropType = 1 Then
                         'if this is a row drag/drop operation
                         DragDropTargetIndex = Me.HitTest(ClientPoint.X, ClientPoint.Y).RowIndex
                         If DragDropTargetIndex > -1 AndAlso DragDropCurrentIndex < Me.RowCount - 1 Then
                             DragDropCurrentIndex = -1
                             Dim SourceRow As DataGridViewRow = TryCast(drgevent.Data.GetData(GetType(DataGridViewRow)), DataGridViewRow)
                             Me.Rows.RemoveAt(DragDropSourceIndex)
                             Me.Rows.Insert(DragDropTargetIndex, SourceRow)
                             Me.Rows(DragDropTargetIndex).Selected = True
                             Me.CurrentCell = Me(0, DragDropTargetIndex)
                             'end if
                         End If
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnDragDrop(drgevent)
         End Sub
         'end OnDragDrop
         Protected Overloads Overrides Sub OnCellPainting(ByVal e As DataGridViewCellPaintingEventArgs)
             'draws red drag/drop target indicator lines if necessary
             If DragDropCurrentIndex > -1 Then
                 If DragDropType = 0 Then
                     'column drag/drop
                     If e.ColumnIndex = DragDropCurrentIndex AndAlso DragDropCurrentIndex < Me.ColumnCount - 1 Then
                         'if this cell is in the same column as the mouse cursor
                         Dim p As New Pen(Color.Red, 1)
                         e.Graphics.DrawLine(p, e.CellBounds.Left - 1, e.CellBounds.Top, e.CellBounds.Left - 1, e.CellBounds.Bottom)
                         'end if
                     End If
 ElseIf DragDropType = 1 Then
                     'row drag/drop
                     If e.RowIndex = DragDropCurrentIndex AndAlso DragDropCurrentIndex < Me.RowCount - 1 Then
                         'if this cell is in the same row as the mouse cursor
                         Dim p As New Pen(Color.Red, 1)
                         e.Graphics.DrawLine(p, e.CellBounds.Left, e.CellBounds.Top - 1, e.CellBounds.Right, e.CellBounds.Top - 1)
                         'end if
                     End If
                     'end if
                 End If
             End If
             'end if
             MyBase.OnCellPainting(e)
         End Sub
         'end OnCellPainting
     End Class
     'end class
 End Namespace
 'end namespace
 
Back
Top