Drag Drop Copy entire row - databound DGV to unbound DGV

Ultrawhack

Well-known member
Joined
Jul 5, 2006
Messages
164
Location
Canada
Programming Experience
3-5
I need to drag drop & copy entire row contents from a Source databound datagridview to a Target unbound datagridview.

Source is set to SelectionMode fullrowselect and multiselect is false.

I am not sure how to achieve this and I have not been able to find relevant articles on this.

Thanks for any help !
 
Last edited:
There most likely is a way. But i don't see any reason why you can't implement this functionality yourself. In the mouse down event you can get the row thats has been selected and copy it to an array, a datatable( bit excessive) whilst there hasn't been a mouse up event you can track the mouse position and identify the control that the mouse is over by its location, if it's a DGV then 'listen' for a mouse up event if there is copy the data in the array to the DGV. It may take a bit of thinking about but it's not gonna take long to work out.
 
Paszt, thanks for that DataGridViewEx link. It's very tempting to use that but it's only meant for databound. I am already using the dragdrop reorder code from dgv faq in my unbound Target DGV and that works fine.

And I agree with vis781 that it can be achieved programatically. But the values in my source columns contain strings and integers and I am still not sure how to copy mixed content to the array. What about copy to clipboard and then paste into Target row?

I really need help with the code to
trap the row that has been selected and copy mixed content to an array
add row and paste array contents to Target row

Thanks again
 
Well the mixed array isn't a problem if you declare it of the type 'object'. Alternatively you can just have an array of the type string and convert the integers to strings and back again. I would probably go for the object one though.

Maybe event better though if you create a class level variable of the type datarow. In the DGV mousedown event the row will be selected, set the class level datarow object as a memberwise clone of the selected datarow(Thats the bit that troubles me, as i don't know if a memberwise clone will copy the data, without testing it i can't be sure) so as long as there is no mouseup event fired and you have tracked the mouse position outside of the DGV's client area you know that you are 'dragging' If the mouse enters the other DGV's client area and a mouseup event is fired then you can create a new row in the other DGV and add the data from the class level datarow object.
 
Almost there.. can someone please help me over the last problems.. I need to populate unbound target DGV's row from the arraylist
VB.NET:
system.collections
 
[COLOR=blue]Dim [/COLOR][COLOR=black]dataRows [/COLOR][COLOR=blue]As [/COLOR][COLOR=black]ArrayList [/COLOR][COLOR=blue]= New [/COLOR][COLOR=black]ArrayList[/COLOR]
[COLOR=blue]For Each [/COLOR][COLOR=black]dgvr [/COLOR][COLOR=blue]As [/COLOR][COLOR=black]DataGridViewRow [/COLOR][COLOR=blue]In Me[/COLOR][COLOR=black].SourceDataGridView.SelectedRows[/COLOR]
[COLOR=black]dataRows.Add([/COLOR][COLOR=blue]CType[/COLOR][COLOR=black](dgvr.DataBoundItem,System.Data.DataRowView).Row)[/COLOR]
[COLOR=blue]Me[/COLOR][COLOR=black].TargetdataGridView.Rows.Add(dataRows) 'gives me the error "columns need to be added first"[/COLOR]
[COLOR=blue]Next[/COLOR]
 
Ok, so the error is saying that the columns need to be added first right? So.. add the columns my friend

VB.NET:
YourDataGridView.Columns.Add(...
 
if I add a column ie:

VB.NET:
[LEFT]system.collections[/LEFT]
 
[LEFT][COLOR=blue]Dim [/COLOR][COLOR=black]dataRows [/COLOR][COLOR=blue]As [/COLOR][COLOR=black]ArrayList [/COLOR][COLOR=blue]= New [/COLOR][COLOR=black]ArrayList[/COLOR]
[COLOR=blue]For Each [/COLOR][COLOR=black]dgvr [/COLOR][COLOR=blue]As [/COLOR][COLOR=black]DataGridViewRow [/COLOR][COLOR=blue]In Me[/COLOR][COLOR=black].SourceDataGridView.SelectedRows[/COLOR]
[COLOR=black]dataRows.Add([/COLOR][COLOR=blue]CType[/COLOR][COLOR=black](dgvr.DataBoundItem,System.Data.DataRowView).Row)[/COLOR]
[COLOR=blue]Me[/COLOR][COLOR=#000000].TargetdataGridView.Columns.Add("Column 1", "Name")[/COLOR]
[COLOR=blue]Me[/COLOR][COLOR=black].TargetdataGridView.Rows.Add(dataRows) [/COLOR][/LEFT]
 
[LEFT][COLOR=blue]Next[/COLOR][/LEFT]

Target DGV Row1, Column1 gets filled with this -> "System.Collections.ArrayList"

I'm missing a step somewhere and the row is not being populated correctly.
 
Last edited:
I think you are still going to have to add the columns, The datagridview column class has a clone method that it inherits from datagridviewband. You could try creating clones of the source datagridview columns and add them to the unbound DGV
 
back to the drawing board... I tried the datagridviewband method and adding rows

VB.NET:
[COLOR=#0000ff]For Each [/COLOR][COLOR=black]dgvr [/COLOR][COLOR=blue]As [/COLOR][COLOR=black]DataGridViewBand [/COLOR][COLOR=blue]In Me[/COLOR][COLOR=black].SourceDataGridView.SelectedRows
[/COLOR][COLOR=darkgreen]    [/COLOR][COLOR=blue]Me[/COLOR][COLOR=black].TargetdataGridView.Rows.Add(dgvr.Clone) ' new row is added but Row1,Col1 is just filled with "[COLOR=red]DatagridviewRow {Index=-1}[/COLOR]"
[/COLOR][COLOR=blue]Next[/COLOR]
[COLOR=#0000ff]
[/COLOR]

but before this I need to clone the source DGV's columns and headertexts. Any wisdom ?
 
Last edited:
Yea, simplest way is to run a loop. Here's an example...

VB.NET:
Dim MyDGVColumn As DataGridViewColumn
For Each DataCol As DataGridViewColumn In YourBoundDGV.Columns
MyDGVColumn = DataCol.Clone
YourUnBoundDGV.Columns.Add(MyDGVColumn)
Next
 
Ok, drag from databound datagridview1 to unbound datagridview2, also adding the same columns as source if they don't exist already. This is how I would do it (I didn't find any shortcut to adding the row/items on drop):
VB.NET:
Private Sub DataGridView1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles DataGridView1.MouseDown
[COLOR=darkgreen]  'select mousedown row[/COLOR]
  Dim hti As DataGridView.HitTestInfo = DataGridView1.HitTest(e.X, e.Y)
  DataGridView1.Rows(hti.RowIndex).Selected = True
 [COLOR=darkgreen] 'get data[/COLOR]
  Dim obj As DataRowView = CType(DataGridView1.SelectedRows(0).DataBoundItem, System.Data.DataRowView)
  [COLOR=darkgreen]'start dragdrop[/COLOR]
  DataGridView1.DoDragDrop(obj, DragDropEffects.Copy)
End Sub
 
Private Sub DataGridView2_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) _
Handles DataGridView2.DragOver
  If e.Data.GetDataPresent(GetType(DataRowView)) = True Then e.Effect = DragDropEffects.Copy
End Sub
 
Private Sub DataGridView2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) _
Handles DataGridView2.DragDrop
If e.Data.GetDataPresent(GetType(DataRowView)) = True Then
  If DataGridView2.Columns.Count = 0 Then [COLOR=darkgreen]'add columns[/COLOR]
    For Each col As DataGridViewColumn In DataGridView1.Columns
      DataGridView2.Columns.Add(col.Clone)
    Next
  End If
  [COLOR=darkgreen]'get data[/COLOR]
  Dim drow As DataRowView = e.Data.GetData(GetType(DataRowView))
  [COLOR=darkgreen]'add row[/COLOR]
  Dim ix As Integer = DataGridView2.Rows.Add
  [COLOR=darkgreen]'add data items[/COLOR]
  For Each col As DataGridViewColumn In DataGridView2.Columns
    DataGridView2.Item(col.Name, ix).Value = drow.Item(col.Name).ToString
  Next
End If
End Sub
 
JohnH, great stuff as always. Is this code working perfectly for you ?

My DGV1 is SelectionMode fullrowselect and multiselect is false.

When I run it and perform the dragdrop, DGV2's columns are properly cloned and a new row is added but nothing appears in the new row. All cells are blank. Data items are not being added...

What could the matter be ?
 
Last edited:
Not sure why JohnH's code wouldn't work here it looked ok, but here's a working revision for the dragdrop sub....

VB.NET:
Private Sub DataGridView2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) _
Handles DataGridView2.DragDrop
If e.Data.GetDataPresent(GetType(DataRowView)) = True Then
If DataGridView2.Columns.Count = 0 Then 'add columns
For Each col As DataGridViewColumn In DataGridView1.Columns
DataGridView2.Columns.Add(col.Clone)
Next
End If
'get data
Dim drow As DataRowView = e.Data.GetData(GetType(DataRowView))
'add row
Dim ix As Integer = DataGridView2.Rows.Add
'add data items
For i As Integer = 0 To Me.DataGridView2.Columns.Count - 1
Me.DataGridView2.Item(i, ix).Value = drow.Item(i).ToString
Next
End If
End Sub
 
Thanks. With your revision,
1. columns are cloned correctly
2. the new row is being added to DGV2 BUT...
3. column data items were all askew

And I figured out why and its very interesting...

Please try this...
In your databound Source dgv DGV1, go to "Edit Columns" and change the order of your Selected Columns and try the code again.

You will find that the columns appear reordered on dgv1, columns are correctly cloned BUT data items copy all screwy to DGV2

This code works (thank God and you both) but explicitly follows the field order of the underlying datasource and disregards any 'cosmetic' reordering of DGV1's columns. You can imagine the fun if we set AllowUserToReorderColumns=true on dgv1.

How can this issue be fixed ? I'm at a loss on this one.

Another issue is this line in DGV1's mousedown fails if user clicks on any headercell...
DataGridView1.Rows(hti.RowIndex).Selected = True
error: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
 
Last edited:
Back
Top