MouseDown 事件与 CellMouseEnter 事件冲突

MouseDown event conflicts with CellMouseEnter event

我有两个单独运行良好的事件,但一个阻止了另一个。

底部的完整代码和 GUI

目标:
我正在尝试将 TreeNode 拖放到 DataGridView 中,并将我悬停的单元格设置为 selected/highlighted.

突出显示单元格的事件:

 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

拖放事件:

我的问题是(任何)MouseDown 事件会阻止 CellMouseEnter 事件。
我在表单的其他地方尝试了 mousedown-ing,然后将鼠标悬停在 DataGridView 上,但我的 CellMouseEnter 事件不起作用。

结果是项目被放入在鼠标按下之前被选中的单元格中(从技术上讲,这个单元格仍然被选中b/c CellMouseEnter 不会将选中的单元格更新为悬停的单元格)

所以在我看来,我需要构建一个类似于 CellMouseEnter 的自定义事件,它不会被 MouseDown 阻止,但我什至不知道从哪里开始。我尝试了 Peek Definition,但找不到 CellMouseEnter 的实际方法,只是 Public Event CellMouseEnter As DataGridViewCellEventHandler.

有没有更好的方法?

这里是我的拖放事件:

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

退出: 退出子 结束子

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

完整代码:注意一些示例 JSON 在最后的注释中,将其放入 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

示例 JSON 文本框:

{
   "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"
      }
   ]
}

控件及其名称:

我最终使用 HittestInfo 来获取正确的单元格,而不是使用 CellMouseEnter selecting 单元格,我决定删除select 序列开头的所有单元格。我还向 select 正确的树视图项添加了悬停。

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

使用 DragOver() 事件的优势在于,当 Drop() 操作生效时,用户可以获得单元格的视觉反馈,因为鼠标悬停的单元格变为活动并跟随鼠标移动。

您还可以验证鼠标指针下的Cell是否可以接收到drop,如果不能则避免选择它。

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