【问题标题】:Dynamically transform a ListViewItem to a usable Class with Get Function?使用 Get 函数将 ListViewItem 动态转换为可用的类?
【发布时间】:2014-01-19 07:20:19
【问题描述】:

也许这个问题看起来没有任何意义,只是因为这个问题:ObjectListView cast exception (for hit testing)

我想知道在执行时是否有办法将ListViewItem 转换为具有预定义函数的预定义类,该函数将返回项和子项以将其添加到ObjectListView 控件中。

类似这样的:

Dim LVI As New ListViewItem("My Item")
LVI.SubItems.AddRange({"My SubItem 1", "My SubItem 2"})

Dim OwnType = ' ListViewItem transformed into a own type.

FastObjectListView1.SetObjects(OwnType.GET())

可以看到 @Mur Haf 在这里回答How to add a new item into ObjectListView? 以了解我正在尝试做的事情,我只想自动进行动态转换,而无需编写类来添加ObjectListview 中的几个字符串。

【问题讨论】:

  • 它是否被标记为c#,因为您也可以在 c# 中回答问题?还是只是为了吸引更广泛的受众?
  • @Aidiakapi 这是因为我可以将 C# 代码翻译成 VBNET,或者至少我可以尝试一下,我可以使用 C# 工作解决方案,不用担心,谢谢您的评论

标签: c# .net vb.net types objectlistview


【解决方案1】:

假设预定义类是模型示例song,来自OLV site

Public Class Song

    Public Sub New()
        Me.New(String.Empty, DateTime.Now, 0)
    End Sub

    Public Sub New(title As String, lastPlayed As DateTime, rating As Integer)
        Me.Title = title
        Me.LastPlayed = lastPlayed
        Me.Rating = rating
    End Sub

    Public Property Title() As String

    Public Property LastPlayed() As DateTime

    Public Property Rating() As Integer

    Public Function GetSizeInMb() As Single
        Return 1.2
    End Function

End Class

以下假设 ListViewItem 已填充:

  • 标题
    • 尺寸
    • 上次播放
    • 排名

请注意,OLV 方法 SetObjects 接受 IEnumerable 对象,因此我们将返回 List(T) 对象。 (与 OP 中链接的“Get”方法相同。)现在,将这些扩展方法添加到 Module

Public Module MyExtensions

    <System.Runtime.CompilerServices.Extension()> _
    Public Function ToSong(item As ListViewItem) As Song
        Dim title As String = item.SubItems(0).Text
        'Dim GetSizeInMb() As Single = Single.Parse(item.SubItems(1).Text) < -Skip, It 's a function in this example.
        Dim lastPlayed = DateTime.Parse(item.SubItems(2).Text)
        Dim rating = Integer.Parse(item.SubItems(3).Text)
        Return New Song(title, lastPlayed, rating)
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](view As ListView) As List(Of Song)
        Dim list As New List(Of Song)
        For Each item As ListViewItem In view.Items
            list.Add(item.ToSong())
        Next
        Return list
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](collection As IEnumerable(Of ListViewItem)) As List(Of Song)
        Dim list As New List(Of Song)
        For Each item As ListViewItem In collection
            list.Add(item.ToSong())
        Next
        Return list
    End Function

End Module

用法:

单身ListViewItem

Dim item As ListViewItem = 'Some listviewitem
Me.olvSongs.SetObjects({item.ToSong()})

多个ListViewItem:

Dim item1 As ListViewItem = 'Some listviewitem
Dim item2 As ListViewItem = 'Some listviewitem
Dim item3 As ListViewItem = 'Some listviewitem
Me.olvSongs.SetObjects({item1, item2, item3}.[Get]())

或者ListView中包含的所有项目:

Dim view As ListView = 'Some listview
Me.olvSongs.SetObjects(view.[Get]())

选项 2 - “界面方式”

下一个选项更具动态性。通过在您的预定义类中实现接口IMergable(T),所有将支持Get 方法。

Public Interface IMergable(Of T)
    Sub Merge(item As T)
End Interface

Public Module MyExtensions

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](Of T)(item As ListViewItem) As List(Of T)
        Dim list As New List(Of T)
        Dim obj As T = Activator.CreateInstance(Of T)()
        If (GetType(T).IsAssignableFrom(GetType(IMergable(Of ListViewItem)))) Then
            DirectCast(obj, IMergable(Of ListViewItem)).Merge(item)
            list.Add(obj)
        End If
        Return list
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](Of T)(view As ListView) As List(Of T)
        Dim list As New List(Of T)
        If (GetType(T).IsAssignableFrom(GetType(IMergable(Of ListViewItem)))) Then
            Dim obj As T = Nothing
            For Each item As ListViewItem In view.Items
                obj = Activator.CreateInstance(Of T)()
                DirectCast(obj, IMergable(Of ListViewItem)).Merge(item)
                list.Add(obj)
            Next
        End If
        Return list
    End Function

End Module

实施:

Public Class Song
    Implements IMergable(Of ListViewItem)

    ...

    Private Sub Merge(item As ListViewItem) Implements IMergable(Of ListViewItem).Merge
        If (item Is Nothing) Then
            Throw New ArgumentNullException("item")
        End If
        Me.Title = item.SubItems(0).Text
        'Me.GetSizeInMb = Single.Parse(item.SubItems(1).Text) < -Skip, It 's a function in this example.
        Me.LastPlayed = DateTime.Parse(item.SubItems(2).Text)
        Me.Rating = Integer.Parse(item.SubItems(3).Text)
    End Sub

End Class

用法:

Me.olvSongs.SetObjects(myListView.[Get](Of Song)())
Me.olvSongs.SetObjects(myListViewItem.[Get](Of Song)())

Me.olvSongs.SetObjects(myListView.[Get](Of PreDefClassType1)())
Me.olvSongs.SetObjects(myListView.[Get](Of PreDefClassType2)())

选项 3 - “反射方式”

此示例仅支持IConvertible 数据类型。

Public Module MyExtensions

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](Of T)(view As ListView, ParamArray members As String()) As List(Of T)
        Dim list As New List(Of ListViewItem)
        For Each item As ListViewItem In view.Items
            list.Add(item)
        Next
        Return list.Get(Of T)(members)
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](Of T)(item As ListViewItem, ParamArray members As String()) As List(Of T)
        Return New ListViewItem() {item}.Get(Of T)(members)
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function [Get](Of T)(collection As IEnumerable(Of ListViewItem), ParamArray members As String()) As List(Of T)
        Dim list As New List(Of T)
        Dim length As Integer = (members.Length - 1)
        If (length > -1) Then

            Dim type As Type = GetType(T)
            Dim info As KeyValuePair(Of MemberInfo, Type)() = New KeyValuePair(Of MemberInfo, Type)(length) {}

            For index As Integer = 0 To length
                For Each m As MemberInfo In type.GetMember(members(index), (MemberTypes.Method Or MemberTypes.Property), (BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.DeclaredOnly))
                    If (m.MemberType = MemberTypes.Property) Then
                        With DirectCast(m, PropertyInfo)
                            If (.CanWrite AndAlso (.GetIndexParameters().Length = 0)) Then
                                info(index) = New KeyValuePair(Of MemberInfo, Type)(m, .PropertyType)
                                Exit For
                            End If
                        End With
                    ElseIf (m.MemberType = MemberTypes.Method) Then
                        With DirectCast(m, MethodInfo)
                            Dim params As ParameterInfo() = .GetParameters()
                            If (params.Length = 1) Then
                                info(index) = New KeyValuePair(Of MemberInfo, Type)(m, params(0).ParameterType)
                                Exit For
                            End If
                        End With
                    End If
                Next
            Next

            For Each item As ListViewItem In collection
                Dim obj As T = Activator.CreateInstance(Of T)()
                Dim ict As Type = GetType(IConvertible)
                For index As Integer = 0 To length
                    Dim pair As KeyValuePair(Of MemberInfo, Type) = info(index)
                    If (Not pair.Key Is Nothing) Then
                        If (ict.IsAssignableFrom(pair.Value)) Then
                            If (pair.Key.MemberType = MemberTypes.Property) Then
                                DirectCast(pair.Key, PropertyInfo).SetValue(obj, System.Convert.ChangeType(item.SubItems(index).Text, pair.Value), Nothing)
                            Else
                                DirectCast(pair.Key, MethodInfo).Invoke(obj, System.Convert.ChangeType(item.SubItems(index).Text, pair.Value))
                            End If
                        Else
                            'TODO: Support other data types.
                            'If (pair.Key.MemberType = MemberTypes.Property) Then
                            'DirectCast(pair.Key, PropertyInfo).SetValue(obj, item.SubItems(index).Text, Nothing)
                            'Else
                            'DirectCast(pair.Key, MethodInfo).Invoke(obj, New Object() {item.SubItems(index).Text})
                            'End If
                        End If
                    End If
                Next
                list.Add(obj)
            Next

        End If
        Return list
    End Function

End Module

用法:

    Me.olvSongs.SetObjects(myListView.[Get](Of Song)("Title", "GetSizeInMb", "LastPlayed", "Rating"))
    Me.olvSongs.SetObjects(myListViewItem.[Get](Of Song)("Title", "GetSizeInMb", "LastPlayed", "Rating"))

    Me.olvSongs.SetObjects(myListView.[Get](Of PreDefClassType1)("Prop1", "Prop2", "Prop3"))
    Me.olvSongs.SetObjects(myListView.[Get](Of PreDefClassType2)("PropA", "PropB", "PropC"))

【讨论】:

  • +1 谢谢,但这对我的意图不起作用,我仍然无法将该 owntype 添加到 ObjectListView,我还尝试添加一个“Get”函数,如上述问题中所述,但是我不能。
  • @ElektroStudios 谢谢!我已经编辑了我的答案,因为可能有点不清楚:)
  • 我对这种方法不太满意,因为它仍然需要手动编写一个 Class 来添加 listviewitem 并手动编写一个 Extension 方法来转换它,我的意图显然是避免硬编码它与 OLV 所说的不同且更容易,无论如何,我很欣赏您所花费的时间,我会将答案标记为已接受,唯一的问题是我在 ObjectListView 中看不到任何项目(我添加了一些列),您的代码不会抛出任何错误,只是 ObjectListView 中的项目说“(null)”,我错过了什么?再次感谢
  • @ElektroStudios 我添加了一些其他选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多