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

时间:2009-12-08 16:06:40

标签: compact-framework treeview windows-mobile-6 checked

我一直在升级现有的.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

4 个答案:

答案 0 :(得分:1)

Hydroslide:回答你的第一个问题,是的,我看到了这种行为。对于你的第二个问题:不,我还没有找到解决方案。

我在VS2K8中开发了一个针对CF 3.5 SP1的应用程序。就像你的应用程序一样,我的几代设备都可以使用我的应用程序。但是,我在Windows Mobile 6.5上遇到过这个TreeView问题。

在我所有的WM 6.5手机(HTC Pure(ST6356),HTC Tilt 2和HTC Imagio) - 以及WM 6.5模拟器中 - TreeView的复选框功能失败。单击复选框几乎总是会使复选标记设置为仅在几毫秒后清除(反之亦然)。我发现可靠地强制勾选“粘贴”的唯一方法是双击复选框。听起来很熟悉,Hydroslide?

除了这种奇怪的行为之外,这些TreeView的外观在较新的HTC手机上被改变,以包括节点之间增加的空白区域,可能是为了通过手指或拇指更容易操作。比较:@ http://ftp.agconnections.com/treeviews.png。 (删除链接之前的@。必要因为StackOverflow首先鼓励我发布“详细和具体”的问题,然后阻止我创建包含多个超链接的帖子。很好。)有趣的是,WM 6.5模拟器显示treeview没有任何额外的空格,但仍然显示检查/取消检查问题。

我创建了一个仅包含标准树视图和几个节点的准系统项目,其行为与我的生产项目的行为相同:http://ftp.agconnections.com/TreeViewTest.zip。我在AfterCheck事件中设置了一个断点,并且发现 - 正如Hydroslide所做的那样 - 它只在单击时发射一次。

我很震惊,我们两个人之外没有人抱怨过这种行为。

等待修复此问题的客户开始堆积,其中一些人的理解有些不足。非常感谢任何建议。

杰森珀塞尔

答案 1 :(得分:1)

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

要显示此信息,您可以点击复选框,将手指放在屏幕上并拖动复选框。它将从MouseDown事件中检查并保持检查状态,因为当您从不同位置抬起手指时不会触发MouseUp事件。同样适用于点击复选框并拖动。

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

以下是关于WndProcHooker的MSDN article链接。下面是我的TreeViewInherit类的代码。虽然这有效,但我仍然感到惊讶的是,这些是我必须努力才能实现这一目标。此外,我并不期待MS修复此问题,因此在此过程中打破了我的解决方法。

    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

祝你好运!

答案 2 :(得分:1)

答案 3 :(得分:1)

为了解决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询问了答案,他们给了我们一个解决方法,其中包括捕获点击并根据需要选中或取消选中复选框。还没有累,但如果它能完成这项工作我也会发布。