树节点检查在 Windows Mobile 6.5 上运行的 Compact Framework 3.5 中 TreeView 的行为

发布于 2024-08-14 04:06:09 字数 3561 浏览 2 评论 0原文

我一直在升级现有的 .NET Windows Mobile 应用程序,以使用 3.5 版本的紧凑框架并在 Windows Mobile 6.5 上运行。我有一个带有 TreeView 的表单。 TreeView.Checkboxes 属性设置为 true,以便每个节点都有一个复选框。这在所有以前版本的 Windows Mobile 中都不会产生任何问题。

然而,在版本 6.5 中,当您单击复选框时,它似乎会立即选中,然后立即取消选中。但它只会引发一次 AfterCheck 事件。我可以粘住支票的唯一方法是双击它(这是错误的行为)。

有人见过这种行为吗?有谁知道它的解决方法?

我附上了一份简单的测试表格。将此表单转储到针对 Windows Mobile 6 的 Visual Studio 2008 智能设备应用程序中即可明白我的意思。

Public Class frmTree
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "
Public Sub New()
    MyBase.new()
    ' This call is required by the Windows Form Designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

End Sub

'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing AndAlso components IsNot Nothing Then
        components.Dispose()
    End If
    MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
Private mainMenu1 As System.Windows.Forms.MainMenu

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.  
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
    Dim TreeNode1 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node0")
    Dim TreeNode2 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node2")
    Dim TreeNode3 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node3")
    Dim TreeNode4 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node4")
    Dim TreeNode5 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node1")
    Dim TreeNode6 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node5")
    Dim TreeNode7 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node6")
    Dim TreeNode8 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node7")
    Me.mainMenu1 = New System.Windows.Forms.MainMenu
    Me.TreeView1 = New System.Windows.Forms.TreeView
    Me.SuspendLayout()
    '
    'TreeView1
    '
    Me.TreeView1.CheckBoxes = True
    Me.TreeView1.Location = New System.Drawing.Point(37, 41)
    Me.TreeView1.Name = "TreeView1"
    TreeNode2.Text = "Node2"
    TreeNode3.Text = "Node3"
    TreeNode4.Text = "Node4"
    TreeNode1.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode2, TreeNode3, TreeNode4})
    TreeNode1.Text = "Node0"
    TreeNode6.Text = "Node5"
    TreeNode7.Text = "Node6"
    TreeNode8.Text = "Node7"
    TreeNode5.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode6, TreeNode7, TreeNode8})
    TreeNode5.Text = "Node1"
    Me.TreeView1.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode1, TreeNode5})
    Me.TreeView1.Size = New System.Drawing.Size(171, 179)
    Me.TreeView1.TabIndex = 0
    '
    'frmTree
    '
    Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
    Me.AutoScroll = True
    Me.ClientSize = New System.Drawing.Size(240, 268)
    Me.Controls.Add(Me.TreeView1)
    Me.Menu = Me.mainMenu1
    Me.Name = "frmTree"
    Me.Text = "frmTree"
    Me.ResumeLayout(False)

End Sub
#End Region

End Class

I have been upgrading an existing .NET Windows Mobile application to use the 3.5 version of the compact framework and to run on Windows Mobile 6.5. I have a form with a TreeView. The TreeView.Checkboxes property is set to true so that each node has a check box. This gives no trouble in all previous versions of Windows Mobile.

However, in version 6.5 when you click on a check box it appears to check and then uncheck instantaneously. But it only raises the AfterCheck event once. The only way I can get a check to stick is by double clicking it (which is the wrong behavior).

Has anyone seen this behavior? Does anyone know of a workaround for it?

I have included a simple test form. Dump this form into a Visual Studio 2008 Smart Device application targeted at Windows Mobile 6 to see what I mean.

Public Class frmTree
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "
Public Sub New()
    MyBase.new()
    ' This call is required by the Windows Form Designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

End Sub

'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing AndAlso components IsNot Nothing Then
        components.Dispose()
    End If
    MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
Private mainMenu1 As System.Windows.Forms.MainMenu

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.  
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
    Dim TreeNode1 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node0")
    Dim TreeNode2 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node2")
    Dim TreeNode3 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node3")
    Dim TreeNode4 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node4")
    Dim TreeNode5 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node1")
    Dim TreeNode6 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node5")
    Dim TreeNode7 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node6")
    Dim TreeNode8 As System.Windows.Forms.TreeNode = New System.Windows.Forms.TreeNode("Node7")
    Me.mainMenu1 = New System.Windows.Forms.MainMenu
    Me.TreeView1 = New System.Windows.Forms.TreeView
    Me.SuspendLayout()
    '
    'TreeView1
    '
    Me.TreeView1.CheckBoxes = True
    Me.TreeView1.Location = New System.Drawing.Point(37, 41)
    Me.TreeView1.Name = "TreeView1"
    TreeNode2.Text = "Node2"
    TreeNode3.Text = "Node3"
    TreeNode4.Text = "Node4"
    TreeNode1.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode2, TreeNode3, TreeNode4})
    TreeNode1.Text = "Node0"
    TreeNode6.Text = "Node5"
    TreeNode7.Text = "Node6"
    TreeNode8.Text = "Node7"
    TreeNode5.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode6, TreeNode7, TreeNode8})
    TreeNode5.Text = "Node1"
    Me.TreeView1.Nodes.AddRange(New System.Windows.Forms.TreeNode() {TreeNode1, TreeNode5})
    Me.TreeView1.Size = New System.Drawing.Size(171, 179)
    Me.TreeView1.TabIndex = 0
    '
    'frmTree
    '
    Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
    Me.AutoScroll = True
    Me.ClientSize = New System.Drawing.Size(240, 268)
    Me.Controls.Add(Me.TreeView1)
    Me.Menu = Me.mainMenu1
    Me.Name = "frmTree"
    Me.Text = "frmTree"
    Me.ResumeLayout(False)

End Sub
#End Region

End Class

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

这个俗人 2024-08-21 04:06:09

我能够为此创建一个解决方法,但必须采取极端措施才能做到这一点。出现我们所看到的行为似乎是因为 Click 事件是由 MouseDown 和 MouseUp 事件触发的(而不是像 Windows 或以前版本中那样仅由鼠标向上触发)。

要显示这一点,您可以先点击复选框,将手指放在屏幕上,然后将其拖出复选框。它将在 MouseDown 事件中被选中,并且将保持选中状态,因为当您从不同位置抬起手指时,不会触发 MouseUp 事件。点击复选框并拖动也同样有效。

为了防止双击行为,您必须抑制 MouseDown 或 MouseUp 事件之一。我最终创建了一个继承 TreeView 的控件,并使用 WndProcHooker 挂钩 OnMouseDown 方法并将其标记为已处理,以便 MouseDown 事件永远不会真正被触发。我认为这是最有意义的(当你抬起它时,你必须将手指放在复选框上)。

以下是有关 WndProcHooker 的 MSDN 文章的链接。下面是我的 TreeViewInherit 类的代码。虽然这可行,但我仍然惊讶于我必须付出如此多的努力才能实现这一目标。此外,我并不期待微软修复此问题的那一天,从而破坏了我在此过程中的解决方法。

    Imports System.Windows.Forms
Imports Microsoft.WindowsCE.Forms

Public Class TreeViewInherit
    Inherits System.Windows.Forms.TreeView

#Region " Variables "
    Private mBlnHandleMouseDown As Boolean
#End Region

#Region " Methods "

    Public Sub New()
    MyBase.New()

    'Set the Handle Mouse Down based on the OS. if 6.5 and up, then handle it.
    mBlnHandleMouseDown = (System.Environment.OSVersion.Version.Major >= 5 AndAlso System.Environment.OSVersion.Version.Minor >= 2 AndAlso System.Environment.OSVersion.Version.Build >= 21234)
    If mBlnHandleMouseDown Then
        WndProcHooker.HookWndProc(Me, New WndProcHooker.WndProcCallback(AddressOf Me.WM_LButtonDown_Handler), Win32.WM_LBUTTONDOWN)
    End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
    'Don't Call the Base to prevent the extra event from firing
    If Not mBlnHandleMouseDown Then
        MyBase.OnMouseDown(e)
    End If
    End Sub

#End Region

#Region " Events "
    Private Function WM_LButtonDown_Handler(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer, ByRef handled As Boolean) As Integer
    Try
        Me.Capture = False

        Dim lastCursorCoordinates As Win32.POINT = Win32.LParamToPoint(lParam)
        If Me.ClientRectangle.Contains(lastCursorCoordinates.X, lastCursorCoordinates.Y) Then
        OnMouseDown(New MouseEventArgs(MouseButtons.Left, 1, lastCursorCoordinates.X, lastCursorCoordinates.Y, 0))
        End If
        handled = True
        Return 0
    Catch ex As Exception
        Throw
    End Try
    End Function
#End Region

End Class

祝你好运!

I was able to create a workaround for this, but had to go to extreme measures to do so. It appears that the behavior we are seeing occurs because the Click event is being fired both from the MouseDown and the MouseUp events (instead of just the mouse up as it would in Windows or previous versions).

To show this, you can start by tapping on the checkbox, leaving your finger on the screen and dragging off the check box. It will become checked from the MouseDown event and will stay checked because the MouseUp event is not fired when you lift your finger from a different position. The same works for tapping off the checkbox and dragging on.

In order to prevent the double click behavior you must suppress one of the MouseDown or MouseUp events. I ended up creating a control that inherited the TreeView and used WndProcHooker to hook the OnMouseDown method and mark it as handled so that the MouseDown Event never actually gets fired. I figured that made the most sense (you must have your finger over the checkbox when you lift it).

Here is a link to the MSDN article about the WndProcHooker. Below is my code for my TreeViewInherit class. While this works, I am still astonished that these are the lengths I have to go to to get this working. Additionally, I am not looking forward to the day MS fixes this and thus breaks my workaround in the process.

    Imports System.Windows.Forms
Imports Microsoft.WindowsCE.Forms

Public Class TreeViewInherit
    Inherits System.Windows.Forms.TreeView

#Region " Variables "
    Private mBlnHandleMouseDown As Boolean
#End Region

#Region " Methods "

    Public Sub New()
    MyBase.New()

    'Set the Handle Mouse Down based on the OS. if 6.5 and up, then handle it.
    mBlnHandleMouseDown = (System.Environment.OSVersion.Version.Major >= 5 AndAlso System.Environment.OSVersion.Version.Minor >= 2 AndAlso System.Environment.OSVersion.Version.Build >= 21234)
    If mBlnHandleMouseDown Then
        WndProcHooker.HookWndProc(Me, New WndProcHooker.WndProcCallback(AddressOf Me.WM_LButtonDown_Handler), Win32.WM_LBUTTONDOWN)
    End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
    'Don't Call the Base to prevent the extra event from firing
    If Not mBlnHandleMouseDown Then
        MyBase.OnMouseDown(e)
    End If
    End Sub

#End Region

#Region " Events "
    Private Function WM_LButtonDown_Handler(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer, ByRef handled As Boolean) As Integer
    Try
        Me.Capture = False

        Dim lastCursorCoordinates As Win32.POINT = Win32.LParamToPoint(lParam)
        If Me.ClientRectangle.Contains(lastCursorCoordinates.X, lastCursorCoordinates.Y) Then
        OnMouseDown(New MouseEventArgs(MouseButtons.Left, 1, lastCursorCoordinates.X, lastCursorCoordinates.Y, 0))
        End If
        handled = True
        Return 0
    Catch ex As Exception
        Throw
    End Try
    End Function
#End Region

End Class

Good Luck!

守护在此方 2024-08-21 04:06:09

为了解决 AfterCheck 事件未触发的问题,我发现我可以单击节点,然后使用它来调用 AfterCheck,这可以工作,但我随后发现 AfterCheck 在复选框状态更改之前被调用,因此改为引发我自己的事件并妥善处理。


Imports System.Windows.Forms
Imports Microsoft.WindowsCE.Forms

Public Class TreeViewInherit
    Inherits System.Windows.Forms.TreeView

    'Occurs when the user clicks a TreeNode with the mouse.
    Public Event MouseDownOveride(ByVal node As TreeNode)

#Region " Variables "
    Private mBlnHandleMouseDown As Boolean
#End Region

#Region " Methods "



    Public Sub New()
        MyBase.New()

        'Set the Handle Mouse Down based on the OS. if 6.5 and up, then handle it.
        mBlnHandleMouseDown = (System.Environment.OSVersion.Version.Major >= 5 AndAlso System.Environment.OSVersion.Version.Minor >= 2 AndAlso System.Environment.OSVersion.Version.Build >= 21234)
        If mBlnHandleMouseDown Then
            WndProcHooker.HookWndProc(Me, New WndProcHooker.WndProcCallback(AddressOf Me.WM_LButtonDown_Handler), Win32.WM_LBUTTONDOWN)
        End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        'Don't Call the Base to prevent the extra event from firing
        If Not mBlnHandleMouseDown Then
            MyBase.OnMouseDown(e)
        End If
    End Sub


    Private Function FindTreeNodeFromHandle(ByVal tnc As TreeNodeCollection, ByVal handle As IntPtr) As TreeNode
        For Each tn As TreeNode In tnc
            If tn.Handle = handle Then
                Return tn
            End If
            ' we couldn't have clicked on a child of this node if this node
            ' is not expanded!
            If tn.IsExpanded Then
                Dim tn2 As TreeNode = FindTreeNodeFromHandle(tn.Nodes, handle)
                If tn2 IsNot Nothing Then
                    Return tn2
                End If
            End If
        Next
        Return Nothing
    End Function


#End Region

#Region " Events "
    Private Function WM_LButtonDown_Handler(ByVal hwnd As IntPtr, ByVal msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer, ByRef handled As Boolean) As Integer
        Try
            Me.Capture = False

            Dim lastCursorCoordinates As Win32.POINT = Win32.LParamToWin32POINT(lParam)

            If Me.ClientRectangle.Contains(lastCursorCoordinates.X, lastCursorCoordinates.Y) Then
                OnMouseDown(New MouseEventArgs(MouseButtons.Left, 1, lastCursorCoordinates.X, lastCursorCoordinates.Y, 0))
            End If
            handled = True


            Dim msgPos As Point = Win32.LParamToPoint(CInt(Win32.GetMessagePos()))
            msgPos = Me.PointToClient(msgPos)

            ' check to see if the click was on an item
            Dim hti As New Win32.TVHITTESTINFO()
            hti.pt.X = msgPos.X
            hti.pt.Y = msgPos.Y
            Dim hitem As Integer = Win32.SendMessage(Me.Handle, Win32.TVM_HITTEST, 0, hti)
            Dim htMask As UInteger = (Win32.TVHT_ONITEMICON Or Win32.TVHT_ONITEMLABEL Or Win32.TVHT_ONITEMINDENT Or Win32.TVHT_ONITEMBUTTON Or Win32.TVHT_ONITEMRIGHT Or Win32.TVHT_ONITEMSTATEICON)

            If hti.flags = Win32.TVHT_ONITEMSTATEICON Then
                RaiseEvent MouseDownOveride(FindTreeNodeFromHandle(Me.Nodes, hti.hItem))
            End If


            Return 0
        Catch ex As Exception
            Throw
        End Try
    End Function
#End Region

End Class

工作正常。

我们向 MS 寻求答案,他们给了我们一个解决方法,其中包括捕获点击并根据需要选中或取消选中复选框。还没有厌倦它,但如果它能完成工作,我也会发布它。

To get over the problem of the AfterCheck event not firing I found that I could get the node clicked on and then use that to call AfterCheck, that works but I then found AfterCheck was called before the state of the checkbox had been changed so instead raised my own event and handled it appropriately.


Imports System.Windows.Forms
Imports Microsoft.WindowsCE.Forms

Public Class TreeViewInherit
    Inherits System.Windows.Forms.TreeView

    'Occurs when the user clicks a TreeNode with the mouse.
    Public Event MouseDownOveride(ByVal node As TreeNode)

#Region " Variables "
    Private mBlnHandleMouseDown As Boolean
#End Region

#Region " Methods "



    Public Sub New()
        MyBase.New()

        'Set the Handle Mouse Down based on the OS. if 6.5 and up, then handle it.
        mBlnHandleMouseDown = (System.Environment.OSVersion.Version.Major >= 5 AndAlso System.Environment.OSVersion.Version.Minor >= 2 AndAlso System.Environment.OSVersion.Version.Build >= 21234)
        If mBlnHandleMouseDown Then
            WndProcHooker.HookWndProc(Me, New WndProcHooker.WndProcCallback(AddressOf Me.WM_LButtonDown_Handler), Win32.WM_LBUTTONDOWN)
        End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        'Don't Call the Base to prevent the extra event from firing
        If Not mBlnHandleMouseDown Then
            MyBase.OnMouseDown(e)
        End If
    End Sub


    Private Function FindTreeNodeFromHandle(ByVal tnc As TreeNodeCollection, ByVal handle As IntPtr) As TreeNode
        For Each tn As TreeNode In tnc
            If tn.Handle = handle Then
                Return tn
            End If
            ' we couldn't have clicked on a child of this node if this node
            ' is not expanded!
            If tn.IsExpanded Then
                Dim tn2 As TreeNode = FindTreeNodeFromHandle(tn.Nodes, handle)
                If tn2 IsNot Nothing Then
                    Return tn2
                End If
            End If
        Next
        Return Nothing
    End Function


#End Region

#Region " Events "
    Private Function WM_LButtonDown_Handler(ByVal hwnd As IntPtr, ByVal msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer, ByRef handled As Boolean) As Integer
        Try
            Me.Capture = False

            Dim lastCursorCoordinates As Win32.POINT = Win32.LParamToWin32POINT(lParam)

            If Me.ClientRectangle.Contains(lastCursorCoordinates.X, lastCursorCoordinates.Y) Then
                OnMouseDown(New MouseEventArgs(MouseButtons.Left, 1, lastCursorCoordinates.X, lastCursorCoordinates.Y, 0))
            End If
            handled = True


            Dim msgPos As Point = Win32.LParamToPoint(CInt(Win32.GetMessagePos()))
            msgPos = Me.PointToClient(msgPos)

            ' check to see if the click was on an item
            Dim hti As New Win32.TVHITTESTINFO()
            hti.pt.X = msgPos.X
            hti.pt.Y = msgPos.Y
            Dim hitem As Integer = Win32.SendMessage(Me.Handle, Win32.TVM_HITTEST, 0, hti)
            Dim htMask As UInteger = (Win32.TVHT_ONITEMICON Or Win32.TVHT_ONITEMLABEL Or Win32.TVHT_ONITEMINDENT Or Win32.TVHT_ONITEMBUTTON Or Win32.TVHT_ONITEMRIGHT Or Win32.TVHT_ONITEMSTATEICON)

            If hti.flags = Win32.TVHT_ONITEMSTATEICON Then
                RaiseEvent MouseDownOveride(FindTreeNodeFromHandle(Me.Nodes, hti.hItem))
            End If


            Return 0
        Catch ex As Exception
            Throw
        End Try
    End Function
#End Region

End Class

Works ok.

We asked MS for an answer and they gave us a workaround which involves capturing the click and checking or un-checking the checkbox as desired. Have not tired it yet but if it does the job I will post that as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文