Reputation: 683
I have two events that work fine on their own, but one blocks the other.
Full Code and GUI at bottom
Goal:
I am trying to DragDrop a TreeNode into a DataGridView and have the Cell I am hovering over be selected/highlighted.
Event that highlights cell:
Public Sub DataGridView1_CellMouseEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellMouseEnter
Try
Me.DataGridView1.CurrentCell = Me.DataGridView1(DataGridView1.Columns(e.ColumnIndex).DisplayIndex, DataGridView1.Rows(e.RowIndex).Index)
Catch
End Try
End Sub
Events for drag and Drop:
My issue is that (any) MouseDown event blocks the CellMouseEnter event.
I tried mousedown-ing elsewhere in the Form and then hovered over the DataGridView and my CellMouseEnter
event did not work.
The result is that the item is dropped into the cell that was selected BEFORE the MouseDown (technically this Cell is still selected b/c CellMouseEnter doesn't update the selected Cell to the hovered Cell)
So the way I see it, I need to build a custom event similar to CellMouseEnter
that isn't blocked by MouseDown, but I wouldn't even know where to start. I tried Peek Definition, but I couldn't find the actual method for CellMouseEnter
, just
Public Event CellMouseEnter As DataGridViewCellEventHandler
.
Is there a better way?
Here my drag and drop events:
Private Sub TreeView1_MouseDown(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseDown
move_item = True
End Sub
Private Sub TreeView1_MouseMove(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseMove
If move_item Then
On Error GoTo quit
Dim item2move As New Label
item2move.Text = TreeView1.SelectedNode.Text
item2move.DoDragDrop(item2move.Text, DragDropEffects.Copy)
Debug.Print(TreeView1.SelectedNode.Text)
End If
move_item = False
quit: Exit Sub End Sub
Private Sub DataGridView1_DragEnter(sender As Object, e As DragEventArgs) Handles DataGridView1.DragEnter
If (e.Data.GetDataPresent(DataFormats.Text)) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
Private Sub DataGridView1_DragDrop(sender As Object, e As DragEventArgs) Handles DataGridView1.DragDrop
With DataGridView1
Dim Col As Integer = .CurrentCell.ColumnIndex
Dim row As Integer = .CurrentCell.RowIndex
.Item(Col, row).Value = e.Data.GetDataPresent(DataFormats.Text)
End With
End Sub
Full Code: Note Some sample JSON is in the comment at the end, put that in the RichtextBox - rtb_inputjson
:
Public Class Form1
Dim move_item As Boolean
'Add some rows to the treemap on load
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
For i = 1 To 20
DataGridView1.Rows.Add()
Next
End Sub
'JSON to treemap
Private Sub btn_jsontotreemap_Click(sender As Object, e As EventArgs) Handles btn_jsontotreemap.Click
Try
Dim json As String = rtb_inputjson.Text
Dim obj As New JObject
obj = JObject.Parse(json)
TreeView1.Nodes.Clear()
Dim parent As TreeNode = Json2Tree(obj)
parent.Text = "Root Object"
TreeView1.Nodes.Add(parent)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Function Json2Tree(ByVal obj As JObject) As TreeNode
'creates the parent node
Dim parent As TreeNode = New TreeNode()
'loop through the obj all token should be pair <key, value>
For Each token In obj
parent.Text = token.Key.ToString()
'create child node
Dim child As TreeNode = New TreeNode()
child.Text = token.Key.ToString()
'self call :)
If token.Value.Type.ToString() = "Object" Then
Dim o As JObject = CType(token.Value, JObject)
child = Json2Tree(o)
child.Text = token.Key.ToString()
parent.Nodes.Add(child)
'but if it is an array...
ElseIf token.Value.Type.ToString() = "Array" Then
Dim ix As Integer = -1
For Each itm In token.Value
'check each item of the array to see if they are objects or arrays
If itm.Type.ToString() = "Object" Then
Dim objTN As TreeNode = New TreeNode()
ix += 1
Dim o As JObject = CType(itm, JObject)
'self call :)
objTN = Json2Tree(o)
objTN.Text = token.Key.ToString() & "[" & ix & "]"
child.Nodes.Add(objTN)
ElseIf itm.Type.ToString() = "Array" Then
ix += 1
Dim dataArray As TreeNode = New TreeNode()
For Each i In itm
dataArray.Text = token.Key.ToString() & "[" & ix & "]"
dataArray.Nodes.Add(i.ToString())
Next
child.Nodes.Add(dataArray)
Else
child.Nodes.Add(itm.ToString())
End If
Next
parent.Nodes.Add(child)
Else
If token.Value.ToString() = "" Then child.Nodes.Add("N/A") Else child.Nodes.Add(token.Value.ToString())
parent.Nodes.Add(child)
End If
Next
Return parent
End Function
'drag & drop to datagridview
Private Sub TreeView1_MouseDown(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseDown
move_item = True
End Sub
Private Sub TreeView1_MouseMove(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseMove
If move_item Then
On Error GoTo quit
Dim item2move As New Label
item2move.Text = TreeView1.SelectedNode.Text
item2move.DoDragDrop(item2move.Text, DragDropEffects.Copy)
Debug.Print(TreeView1.SelectedNode.Text)
End If
move_item = False
quit:
Exit Sub
End Sub
Public Sub DataGridView1_CellMouseEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellMouseEnter
Debug.Print("CellMouseEnter event raised")
Try
Me.DataGridView1.CurrentCell = Me.DataGridView1(DataGridView1.Columns(e.ColumnIndex).DisplayIndex, DataGridView1.Rows(e.RowIndex).Index)
Catch
End Try
End Sub
Private Sub DataGridView1_DragDrop(sender As Object, e As DragEventArgs) Handles DataGridView1.DragDrop
With DataGridView1
Dim Col As Integer = .CurrentCell.ColumnIndex
Dim row As Integer = .CurrentCell.RowIndex
.Item(Col, row).Value = e.Data.GetDataPresent(DataFormats.Text)
End With
End Sub
Private Sub DataGridView1_DragEnter(sender As Object, e As DragEventArgs) Handles DataGridView1.DragEnter
If (e.Data.GetDataPresent(DataFormats.Text)) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
End Class
Sample JSON for textbox:
{
"data":[
{
"symbol":"A",
"name":"Agilent Technologies Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"2"
},
{
"symbol":"AA",
"name":"Alcoa Corporation",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"12042"
},
{
"symbol":"AABA",
"name":"Altaba Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"7653"
},
{
"symbol":"AAC",
"name":"AAC Holdings Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"9169"
},
{
"symbol":"AADR",
"name":"AdvisorShares Dorsey Wright ADR",
"date":"2018-03-19",
"isEnabled":true,
"type":"et",
"iexId":"5"
},
{
"symbol":"AAL",
"name":"American Airlines Group Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"8148"
},
{
"symbol":"AAMC",
"name":"Altisource Asset Management Corp Com",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"7760"
},
{
"symbol":"AAME",
"name":"Atlantic American Corporation",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"7"
},
{
"symbol":"AAN",
"name":"Aaron's Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"8"
},
{
"symbol":"AAOI",
"name":"Applied Optoelectronics Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"7790"
},
{
"symbol":"AAON",
"name":"AAON Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"9"
},
{
"symbol":"AAP",
"name":"Advance Auto Parts Inc W/I",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"10"
},
{
"symbol":"AAPL",
"name":"Apple Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"11"
},
{
"symbol":"AAT",
"name":"American Assets Trust Inc.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"12"
},
{
"symbol":"AAU",
"name":"Almaden Minerals Ltd.",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"13"
},
{
"symbol":"AAV",
"name":"Advantage Oil & Gas Ltd",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"14"
},
{
"symbol":"AAWW",
"name":"Atlas Air Worldwide Holdings",
"date":"2018-03-19",
"isEnabled":true,
"type":"cs",
"iexId":"15"
}
]
}
Controls and their Names:
Upvotes: 0
Views: 684
Reputation: 32278
Using the DragOver()
event, you have the advantage that a user can have a visual feedback of the cell when the Drop()
operation will take effect, since the cell where the mouse is hovering becomes active and follows the mouse movement.
You could also verify whether the Cell under the mouse pointer can receive the drop and avoid selecting it if not.
Private Sub dataGridView1_DragEnter(sender As Object, e As DragEventArgs)
e.Effect = If(e.Data.GetDataPresent(DataFormats.Text) = True,
DragDropEffects.Copy,
DragDropEffects.None)
Private Sub dataGridView1_DragDrop(sender As Object, e As DragEventArgs)
'Check whether the current Cell supports this Drop()
DataGridView1.CurrentCell.Value = e.Data.GetDataPresent(DataFormats.Text).ToString()
End Sub
Private Sub dataGridView1_DragOver(sender As Object, e As DragEventArgs)
Dim ClientAreaLocation As Point = dataGridView1.PointToClient(New Point(e.X, e.Y))
Dim CellPosition As DataGridView.HitTestInfo = dataGridView1.HitTest(ClientAreaLocation.X, ClientAreaLocation.Y)
If CellPosition.ColumnIndex > -1 AndAlso CellPosition.RowIndex > -1 Then
'Enable if this Cell supports this Drop()
dataGridView1.CurrentCell = dataGridView1(CellPosition.ColumnIndex, CellPosition.RowIndex)
End If
End Sub
Upvotes: 1
Reputation: 683
I ended up using the HittestInfo to get the right cell and instead of selecting the cell with CellMouseEnter, I decided to deselect all cells at the beginning of the sequence. I also added a hover to select the proper treeview item.
Private Sub TreeView1_MouseDown(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseDown
move_item = True
End Sub
Private Sub TreeView1_MouseMove(sender As Object, e As MouseEventArgs) Handles TreeView1.MouseMove
If move_item Then
On Error GoTo quit
'Deselect all cells in datagridview
DataGridView1.ClearSelection()
DataGridView1.CurrentCell = Nothing
'Begin Drag/drop
Dim item2move As New Label
item2move.Text = TreeView1.SelectedNode.Text
item2move.DoDragDrop(item2move.Text, DragDropEffects.Copy)
End If
move_item = False
quit:
Exit Sub
End Sub
Private Sub DataGridView1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView1.DragEnter
If (e.Data.GetDataPresent(DataFormats.Text)) Then
e.Effect = DragDropEffects.Copy
Else
e.Effect = DragDropEffects.None
End If
End Sub
Private Sub DataGridView1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles DataGridView1.DragDrop
Try
Dim clickedcell As DataGridViewCell
Dim ptscreen As New Point(e.X, e.Y)
Dim ptclient = DataGridView1.PointToClient(ptscreen)
Dim hit As DataGridView.HitTestInfo = DataGridView1.HitTest(ptclient.X, ptclient.Y)
clickedcell = DataGridView1.Rows(hit.RowIndex).Cells(hit.ColumnIndex)
DataGridView1.Item(clickedcell.ColumnIndex, clickedcell.RowIndex).Value = e.Data.GetData(DataFormats.Text).ToString
Catch
End Try
End Sub
Private Sub TreeView1_NodeMouseHover(sender As Object, e As TreeNodeMouseHoverEventArgs) Handles TreeView1.NodeMouseHover
TreeView1.SelectedNode = e.Node
End Sub
Upvotes: 0