首页 > 解决方案 > 多次快速单击时复选框无法正常工作

问题描述

这段代码的作用:

  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

    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

    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

这段代码工作正常。

问题:

当我快速单击时,某些复选框被选中,而有些则没有。例如,有时我检查了父节点,但所有子节点仍未选中。有时父节点未选中,但其子节点仍处于选中状态。

请检查示例图像:

这个

请问这个怎么解决,是不是我电脑的问题?

标签: vb.netvisual-studio-2015treeview

解决方案


发生这种情况是因为默认情况下 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 的类型。

SOQ61299089


有关的


TreeView、Windows 窗体中的 AfterCheck 和 AfterSelect 事件(c#)



推荐阅读