CheckBox не работает должным образом при нажатии несколько раз - PullRequest
2 голосов
/ 19 апреля 2020

Что делает этот код:

  1. Если родительский узел отмечен / не отмечен, также отметьте / снимите флажок со всех дочерних узлов.

  2. Если просто один дочерний узел проверен, также проверьте родительский узел.

    Private Sub TreeView1_AfterCheck(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterCheck
        If updatingTreeView Then Return
        updatingTreeView = True
        CheckNode(e.Node, e.Node.Checked)
        HasCheckedChildNode = 0
        updatingTreeView = False
    End Sub</p>
    
    <p>Private Sub CheckNode(node As TreeNode, isChecked As Boolean)
        If node.Parent IsNot Nothing Then
            HasCheckedNode(node.Parent)
            If Not isChecked And HasCheckedChildNode > 0 Then Return
            node.Parent.Checked = isChecked
        ElseIf node.Parent Is Nothing Then
            For Each cn As TreeNode In node.Nodes
                cn.Checked = isChecked
            Next
        End If
    End Sub</p>
    
    <p>Private Sub HasCheckedNode(node As TreeNode)
        For Each cn As TreeNode In node.Nodes
            If cn.Checked = True Then
                HasCheckedChildNode += 1
            ElseIf cn.Checked = False Then
                HasCheckedChildNode -= 0
            End If
        Next
    End Sub
    

Этот код работает нормально.

Проблема:

Когда я быстро щелкаю, некоторые из флажков отмечены, а некоторые нет. Например, иногда я проверял родительский узел, но все дочерние узлы по-прежнему остаются непроверенными. Иногда родительский узел не отмечен, но его дочерние узлы все еще проверяются.

Пожалуйста, проверьте пример изображения:

this

Как решить эту проблему, это проблема с мой P C?

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Это происходит потому, что TreeView по умолчанию не переключает свойство Check объектов TreeNode при двойном щелчке мыши над областью флажка. Вам необходимо перехватить сообщения WM_LBUTTONDBLCLK, получить TreeViewHitTestInfo точки двойного щелчка и переключить свойство Check, если точка двойного щелчка находится над флажком.

Вот специальный TreeView для этого Кроме того, он решает основную проблему, проверяя / снимая флажки родительского и дочернего узлов ветви, для этого просто включите свойства AutoCheckParents и / или AutoCheckChildren.

Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

<DesignerCategory("Code")>
Public Class DoubleClickCheckTreeView
    Inherits TreeView

#Region "Properties"

    <Category("Behavior"),
        DefaultValue(False)>
    Public Property AutoCheckParents As Boolean = False

    <Category("Behavior"),
        DefaultValue(False)>
    Public Property AutoCheckChildren As Boolean = False

#End Region

#Region "Overrides"

    'Enable DoubleBuffered to reduce the flickering.
    Protected Overrides Sub OnHandleCreated(e As EventArgs)
        SendMessage(Handle,
                    TVM_SETEXTENDEDSTYLE,
                    IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER),
                    IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER))
        MyBase.OnHandleCreated(e)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_LBUTTONDBLCLK AndAlso CheckBoxes Then
            Dim x As Integer = m.LParam.ToInt32() And &HFFFF
            Dim y As Integer = (m.LParam.ToInt32 >> 16) And &HFFFF
            Dim ht As TreeViewHitTestInfo = HitTest(x, y)

            If ht.Node IsNot Nothing AndAlso
                ht.Location = TreeViewHitTestLocations.StateImage Then
                OnBeforeCheck(New TreeViewCancelEventArgs(ht.Node,
                                                          False,
                                                          TreeViewAction.ByMouse))
                ht.Node.Checked = Not ht.Node.Checked
                OnAfterCheck(New TreeViewEventArgs(ht.Node, TreeViewAction.ByMouse))
                m.Result = IntPtr.Zero
                Return
            End If
        End If
        MyBase.WndProc(m)
    End Sub

    Protected Overrides Sub OnAfterCheck(e As TreeViewEventArgs)
        MyBase.OnAfterCheck(e)

        If e.Action = TreeViewAction.Unknown OrElse
            Not CheckBoxes Then Return

        If AutoCheckParents Then
            Dim p = e.Node.Parent

            While p IsNot Nothing
                p.Checked = p.Nodes.Cast(Of TreeNode).Any(Function(x) x.Checked)
                p = p.Parent
            End While
        End If

        If AutoCheckChildren Then
            For Each tn As TreeNode In GetNodes(e.Node)
                tn.Checked = e.Node.Checked
            Next
        End If
    End Sub

#End Region

#Region "Private Methods"

    Private Iterator Function GetNodes(node As TreeNode) As IEnumerable(Of TreeNode)
        For Each n As TreeNode In node.Nodes
            Yield n
            For Each c As TreeNode In GetNodes(n)
                Yield c
            Next
        Next
    End Function

#End Region

#Region "API"

    Private Const TVM_SETEXTENDEDSTYLE As Integer = &H1100 + 44
    Private Const TVM_GETEXTENDEDSTYLE As Integer = &H1100 + 45
    Private Const TVS_EX_DOUBLEBUFFER As Integer = &H4
    Private Const WM_LBUTTONDBLCLK As Integer = &H203

    <DllImport("user32.dll")>
    Private Shared Function SendMessage(ByVal hWnd As IntPtr,
                                       ByVal msg As Integer,
                                       ByVal wp As IntPtr,
                                       ByVal lp As IntPtr) As IntPtr
    End Function

#End Region

End Class
  • Добавьте новый класс для вашего проекта и вставьте этот код.
  • Перестройка.
  • Удалите экземпляр DoubleClickCheckTreeView или измените тип существующего TreeView по умолчанию в Designer.

SOQ61299089


Связанные


События AfterCheck и AfterSelect в TreeView Windows форм (c#)


1 голос
/ 19 апреля 2020

Я бы подумал, что вам придется обрабатывать событие двойного щелчка, когда оно сработало, и я подозреваю, что ваш код для него будет очень похож на ваше событие одиночного щелчка (но кто знает)

...