多次快速单击时 CheckBox 无法正常工作
CheckBox not work properly when clicked on quickly multiple times
此代码的作用:
如果父节点是checked/unchecked,也check/uncheck所有子节点。
如果只检查一个子节点,还要检查父节点。
Private Sub TreeView1_AfterCheck(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterCheck
If updatingTreeView Then Return
updatingTreeView = True
CheckNode(e.Node, e.Node.选中)
已检查子节点 = 0
updatingTreeView = 假
结束子</p>
<p>Private Sub CheckNode(node As TreeNode, isChecked As Boolean)
如果 node.Parent IsNot Nothing 那么
HasCheckedNode(node.Parent)
If Not isChecked And HasCheckedChildNode > 0 Then Return
node.Parent.Checked = isChecked
ElseIf node.Parent 那么什么都不是
For Each cn As TreeNode In node.Nodes
cn.Checked = 已检查
下一个
万一
结束子</p>
<p>Private Sub HasCheckedNode(node As TreeNode)
For Each cn As TreeNode In node.Nodes
如果 cn.Checked = True 那么
HasCheckedChildNode += 1
ElseIf cn.Checked = False 然后
HasCheckedChildNode -= 0
万一
下一个
结束子
这段代码工作正常。
问题:
当我快速点击时,有些复选框被选中,有些则没有
例如。有时我检查了父节点,但所有子节点仍未选中。有时父节点未选中,但其子节点仍处于选中状态。
请检查示例图片:
如何解决这个问题,这是我电脑的问题吗?
我想你必须在双击事件被触发时处理它,我怀疑你的代码看起来与你的单击事件非常相似(但谁知道呢)
发生这种情况是因为 TreeView 默认情况下不会在鼠标双击复选框区域时切换 TreeNode 对象的 Check
属性。需要拦截WM_LBUTTONDBLCLK
消息,获取双击点的TreeViewHitTestInfo
,如果双击点在复选框上方,则切换Check
属性
这是一个自定义的 TreeView,它也解决了主要问题,checking/unchecking 分支的父节点和子节点,只需启用 AutoCheckParents
and/or 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
- 向您的项目添加一个新的 class 并粘贴此代码。
- 重建。
- 删除 DoubleClickCheckTreeView 的实例或更改设计器中现有默认 TreeView 的类型。
Related
◉
此代码的作用:
如果父节点是checked/unchecked,也check/uncheck所有子节点。
如果只检查一个子节点,还要检查父节点。
Private Sub TreeView1_AfterCheck(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterCheck If updatingTreeView Then Return updatingTreeView = True CheckNode(e.Node, e.Node.选中) 已检查子节点 = 0 updatingTreeView = 假 结束子</p> <p>Private Sub CheckNode(node As TreeNode, isChecked As Boolean) 如果 node.Parent IsNot Nothing 那么 HasCheckedNode(node.Parent) If Not isChecked And HasCheckedChildNode > 0 Then Return node.Parent.Checked = isChecked ElseIf node.Parent 那么什么都不是 For Each cn As TreeNode In node.Nodes cn.Checked = 已检查 下一个 万一 结束子</p> <p>Private Sub HasCheckedNode(node As TreeNode) For Each cn As TreeNode In node.Nodes 如果 cn.Checked = True 那么 HasCheckedChildNode += 1 ElseIf cn.Checked = False 然后 HasCheckedChildNode -= 0 万一 下一个 结束子
这段代码工作正常。
问题:
当我快速点击时,有些复选框被选中,有些则没有 例如。有时我检查了父节点,但所有子节点仍未选中。有时父节点未选中,但其子节点仍处于选中状态。
请检查示例图片:
如何解决这个问题,这是我电脑的问题吗?
我想你必须在双击事件被触发时处理它,我怀疑你的代码看起来与你的单击事件非常相似(但谁知道呢)
发生这种情况是因为 TreeView 默认情况下不会在鼠标双击复选框区域时切换 TreeNode 对象的 Check
属性。需要拦截WM_LBUTTONDBLCLK
消息,获取双击点的TreeViewHitTestInfo
,如果双击点在复选框上方,则切换Check
属性
这是一个自定义的 TreeView,它也解决了主要问题,checking/unchecking 分支的父节点和子节点,只需启用 AutoCheckParents
and/or 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
- 向您的项目添加一个新的 class 并粘贴此代码。
- 重建。
- 删除 DoubleClickCheckTreeView 的实例或更改设计器中现有默认 TreeView 的类型。
Related
◉