【问题标题】:Using TreeListView in VB.net在 VB.net 中使用 TreeListView
【发布时间】:2018-06-27 21:39:35
【问题描述】:

我正在创建一个在 VB.NET 中使用 TreeListView 的简单示例(或至少一个我可以遵循的示例),但我遇到了一个问题。当我运行下面的代码时,最初一切正常。我有一棵带有宠物名字分支的宠物主人树。但是在我展开其中一个节点并移动鼠标后,我收到一条错误消息,告诉我无法将字符串对象转换为 petowner 对象(我的对象类)。我明白这意味着什么,但 VS 并没有告诉我错误在哪里,我也不能将它困在 try-catch 中。我正在寻找一些见解。

另外:谁能告诉我我从 C# 到 VB 的转换是否正确;特别是 lambda 函数代替 ChildrenGetter 和 AspectGetter 方法中的委托?我相当肯定这就是错误所在。

提前致谢。

Public Class Form1

Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

    Dim PetOwners As New List(Of PetOwner)
    Dim PetOwner As PetOwner

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Steve"
    PetOwner.PetNames.Add("Bob the Cat")
    PetOwner.PetNames.Add("Snoop the Dog")
    PetOwners.Add(PetOwner)

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Ann"
    PetOwners.Add(PetOwner)

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Joe"
    PetOwner.PetNames.Add("Shoeless")
    PetOwners.Add(PetOwner)

    Try
        tlvPetOwners.CanExpandGetter = Function(po As PetOwner) po.PetNames.Count > 0
        tlvPetOwners.ChildrenGetter = Function(po As Object)
                                          Dim RetVal As Object = Nothing
                                          Try
                                              If TypeOf po Is PetOwner Then
                                                  RetVal = CType(po, PetOwner).PetNames
                                              Else
                                                  RetVal = po
                                              End If
                                          Catch ex As Exception
                                              Debug.Print(ex.ToString)
                                          Finally

                                          End Try

                                          Return RetVal

                                      End Function


        Dim OwnerColumn As New OLVColumn()


        OwnerColumn.AspectGetter = Function(po As Object)
                                       Dim RetVal As Object = Nothing
                                       Try
                                           If TypeOf po Is PetOwner Then
                                               RetVal = CType(po, PetOwner).OwnerName
                                           Else
                                               RetVal = po
                                           End If
                                       Catch ex As Exception
                                           Debug.Print(ex.ToString)
                                       Finally

                                       End Try

                                       Return RetVal

                                   End Function
        tlvPetOwners.Columns.Add(OwnerColumn)

        tlvPetOwners.Roots = PetOwners
    Catch ex As Exception
        Debug.Print(ex.ToString)
    End Try
End Sub

End Class


Public Class PetOwner
    Public OwnerName As String
    Public  PetNames As New List(Of String)
End Class

【问题讨论】:

  • 然后在你的代码上插入断点,然后调试你会发现哪里出错了。
  • 没错,但是 column aspectgetter 方法似乎处于连续循环中。按F5一会儿后。当它停止并且我重新进入 TreeListView 时,循环重新开始,我继续按 F5 一会儿。当然,我从来没有遇到过错误。
  • 抱歉,不是很清楚。循环最终会停止,但是当我用光标重新进入 TreeListView 时,循环会重新开始。我可以做到这一点,因为这似乎是永恒的,而且永远不会出错。直到我删除断点,它才会出错,但不会告诉我在哪里,也不会在任何 Try 子句中遇到异常。
  • 好的,我将在我的窗口中尝试此代码。

标签: .net vb.net treelistview


【解决方案1】:

好的,我想通了,也学到了一些东西(是的,我 - 哈哈)。首先,我得出的结论是我的问题存在于尝试使用字符串列表作为宠物名称,并且没有创建名为 Pet 的自定义对象列表,其属性为 Name 用作 TreeListView 列的 AspectName,例如你会是一个ObjectListView。我不想在我的实际项目中创建一个名称清单(这只是一个测试)。

如果您在 ObjectListView 上尝试这样的操作,您将遇到 AspectName 方法的问题,对于 TreeListView 也是如此。

Private Sub MakeObjectList()

    Dim Pets As New List(Of String)
    Pets.Add("Smokey")
    Pets.Add("Rufus")
    Pets.Add("Petey")
    Pets.Add("Garfield")
    Pets.Add("Ren")
    Pets.Add("Stimpy")
    Pets.Add("Smokey")

    Dim PetCol As New OLVColumn()
    PetCol.Text = "Pets"
    'You would never be able to do this, because you'd have nothing to set it to, and without it your list would never appear.
    'PetCol.AspectGetter = "??????"

    'But using the AspectGetter, you can supply a Lambda, using the pet name itself as the aspect name.
    PetCol.AspectGetter = Function(p As String) p

    olvPets.Columns.Add(PetCol)

    olvPets.SetObjects(Pets)

End Sub

但是,您可以通过对 AspectGetter 方法使用 Lambda 来解决此问题,该方法本质上将宠物名称作为 AspectName 提供。在数据库应用程序中没有用,但如果您只是尝试提供名称清单,则很有用。

然后我决定将这种方法用于 TreeListView。我确实必须创建第二列来保存宠物名称,并在这样做时将 AspectGetter 设置为:

PetColumn.AspectGetter = Function(po As Object)
                                     Dim RetVal As String
                                     If TypeOf po Is String Then
                                         RetVal = CType(po, String)
                                     Else
                                         RetVal = String.Empty
                                     End If
                                     Return RetVal
                                 End Function

诀窍是这一行:

  RetVal = CType(po, String)

这允许您将字符串本身定义为方面名称。

这是我的最终代码。它由必须放在表单上的 ObjectListView (olvPets) 和 TreeListView (tlvPetOwners) 组成。无论如何,我希望这对其他人有所帮助。

Public Class Form1

Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

    MakeTreeView()
    MakeObjectList()

End Sub

Private Sub MakeTreeView()
    Dim PetOwners As New List(Of PetOwner)
    Dim PetOwner As PetOwner

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Steve"
    PetOwner.PetNames.Add("Bob the Cat")
    PetOwner.PetNames.Add("Snoop the Dog")
    PetOwners.Add(PetOwner)

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Ann"
    PetOwners.Add(PetOwner)

    PetOwner = New PetOwner
    PetOwner.OwnerName = "Joe"
    PetOwner.PetNames.Add("Shoeless")
    PetOwners.Add(PetOwner)

    Dim OwnerColumn As New OLVColumn()

    tlvPetOwners.Columns.Add(OwnerColumn)

    Dim PetColumn As New OLVColumn()
    tlvPetOwners.Columns.Add(PetColumn)

    Try
        tlvPetOwners.CanExpandGetter = Function(po As Object)
                                           Dim RetVal As Boolean = False
                                           If TypeOf po Is PetOwner Then
                                               If po.PetNames.Count > 0 Then
                                                   RetVal = True
                                               End If
                                           End If
                                           Return RetVal
                                       End Function

        tlvPetOwners.ChildrenGetter = Function(po As Object) CType(po, PetOwner).PetNames

        OwnerColumn.AspectGetter = Function(po As Object)
                                       Dim RetVal As String = String.Empty
                                       If TypeOf po Is PetOwner Then
                                           RetVal = CType(po, PetOwner).OwnerName
                                       Else
                                           RetVal = String.Empty
                                       End If
                                       Return RetVal
                                   End Function

        PetColumn.AspectGetter = Function(po As Object)
                                     Dim RetVal As String
                                     If TypeOf po Is String Then
                                         RetVal = CType(po, String)
                                     Else
                                         RetVal = String.Empty
                                     End If
                                     Return RetVal
                                 End Function

        tlvPetOwners.SetObjects(PetOwners)
        tlvPetOwners.ExpandAll()

    Catch ex As Exception
        Debug.Print(ex.ToString)
    End Try

End Sub

Private Sub MakeObjectList()

    Dim Pets As New List(Of String)
    Pets.Add("Smokey")
    Pets.Add("Rufus")
    Pets.Add("Petey")
    Pets.Add("Garfield")
    Pets.Add("Ren")
    Pets.Add("Stimpy")
    Pets.Add("Smokey")

    Dim PetCol As New OLVColumn()
    PetCol.Text = "Pets"
    'You would never be able to do this
    'PetCol.AspectGetter = "??????"

    PetCol.AspectGetter = Function(p As String) p

    olvPets.Columns.Add(PetCol)

    olvPets.SetObjects(Pets)

End Sub

End Class

Public Class PetOwner
Public OwnerName As String
Public PetNames As New List(Of String)
End Class

【讨论】:

    【解决方案2】:

    我已经使用 TreeListView 有一段时间了,而不是您的 Lambda 函数,我使用 AddressOf 指向同一空间中的例程..

    With tlv
    
      tlv.BeginUpdate()
    
      .CanExpandGetter = AddressOf b_tlvCanExpandGetter   ! ***** 
      .ChildrenGetter = AddressOf mcol_GetOccupants       ! *****
      .Roots = colRoot   ' Collection of objects to make the root nodes
    
      tlv.EndUpdate()
    
      Application.DoEvents()
      ... etc
    

    然后指向的例程可以使用任何属性、函数等来做出决定或返回值列表。例如

    Function mcol_GetOccupants(ByVal oTI As Object) As List(Of TreeItem)
    
      Dim ti As TreeItem = CType(oTI, TreeItem)
      Select Case ti.ObjectType
    
        Case BaseObject.BaseObjectType.eTypeA
          Return CType(oTI, TypeA).Occupants
    
        Case BaseObject.BaseObjectType.eTypeB,
              BaseObject.BaseObjectType.eTypeC
    
          Return CType(oTI, TypeBC).Occupants
    
        Case BaseObject.BaseObjectType.eTypeD
          Return CType(oTI, TypeD).Occupants
    
        Case Else
          Return New List(Of TreeItem)
      End Select
    
    End Function
    

    我要注意的另一件事是,即使将鼠标移到 TreeListView 上也会触发 RePaint,因此在刷新代码中设置断点是充满危险的。相反,我放了很多 Console.WriteLine 来告诉我发生了什么。这尤其发生在 IDE 覆盖 TreeListView 的小屏幕上,一旦您在断点停止后再次运行,该项目 再次 调用 repaint 来绘制它被覆盖的屏幕 - 这会跳回IDE - 覆盖项目屏幕 - 循环你去..... 因此,如果您确实需要调试刷新代码,请确保 IDE 和项目屏幕不会以任何方式重叠。

    【讨论】:

      猜你喜欢
      • 2013-12-16
      • 2016-09-14
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 2023-02-10
      • 1970-01-01
      • 2013-01-31
      相关资源
      最近更新 更多