This is my current method for populating the sub-items of ListView
controls. I like this method for two reasons...
1) I don't have to keep up with the display order of the columns.
2) If I enable column re-ordering, I don't have to change anything with the code.
So, the question is... Is this a good approach? Can it be improved?
Note: I'm not too happy about declaring Result As Object
. It seems like there should be a better way to handle that, but it's the only way I could get it to working.
Private Function RetrieveItem(Of T)(ByVal displayIndex As Integer) As T
Dim Result As Object = If(GetType(T) Is GetType(ListViewItem), New ListViewItem, New ListViewItem.ListViewSubItem)
Select Case displayIndex
Case ColumnHeader1.DisplayIndex
Result.Text = "First Item"
Result.Tag = "First"
Case (ColumnHeader2.DisplayIndex)
Result.Text = "Second Column"
Result.Tag = "Second"
Case ColumnHeader3.DisplayIndex
Result.Text = "Third Column"
Result.Tag = "Third"
Case ColumnHeader4.DisplayIndex
Result.Text = "Fourth Column"
Result.Tag = "Fourth"
End Select
Return Result
End Function
Example Usage...
Dim item As ListViewItem = RetrieveItem(Of ListViewItem)(0)
For i As Integer = 1 To ListView1.Columns.Count - 1
item.SubItems.Add(RetrieveItem(Of ListViewItem.ListViewSubItem)(i))
Next
ListView1.Items.Add(item)
Here is the example I came up with using @MarkHurd's suggestion of using a Widening CType Operator
...
Private Class LVI
Public Name As String
Public Text As String
Public Tag As Object
Public Sub New(ByVal name As String, ByVal text As String, ByVal tag As Object)
Me.Name = name
Me.Text = text
Me.Tag = tag
End Sub
Public Shared Widening Operator CType(ByVal item As LVI) As ListViewItem
Dim Result As New ListViewItem(item.Text)
Result.Name = item.Name
Result.Tag = item.Tag
Return Result
End Operator
Public Shared Widening Operator CType(ByVal item As LVI) As ListViewItem.ListViewSubItem
Dim Result As New ListViewItem.ListViewSubItem
Result.Text = item.Text
Result.Name = item.Name
Result.Tag = item.Tag
Return Result
End Operator
End Class
Private Function RetrieveItem(ByVal index As Integer) As LVI
Select Case index
Case ColumnHeader1.DisplayIndex : Return New LVI("1", "First Column", "one")
Case ColumnHeader2.DisplayIndex : Return New LVI("2", "Second Column", "two")
Case ColumnHeader3.DisplayIndex : Return New LVI("3", "Third Column", "three")
Case ColumnHeader4.DisplayIndex : Return New LVI("4", "Fourth Column", "four")
Case Else : Return Nothing
End Select
End Function
Example usage...
Dim item As ListViewItem = RetrieveItem(0)
For i As Integer = 1 To ListView1.Columns.Count - 1
item.SubItems.Add(RetrieveItem(i))
Next
ListView1.Items.Add(item)
I like both of these approaches, but I feel like the first is shorter and easier to implement, so I lean towards the first option.
1 Answer 1
If you want to avoid the late bound .Text
and .Tag
you could just create your own private type, say LVI
, containing these two properties and implicit Widening
CType
operators for ListViewItem
and ListViewItem.ListViewSubItem
. Then the Result As New LVI
can be converted on return using Return CType(CTypeDynamic(Result, GetType(T)), T)
in the latest VB.NET.
Without CTypeDynamic
I don't have a working solution yet.
-
1\$\begingroup\$ I was previously unaware of
Widening CType
. Your suggestion looks promising... I think when I get a chance, I will experiment with that approach and see how it turns out. If I like it, I'll post it as an addendum to my question. \$\endgroup\$Drew Chapin– Drew Chapin2012年07月25日 22:09:16 +00:00Commented Jul 25, 2012 at 22:09
Result As Object
." That's not your fault: Microsoft should have at least defined an interface that bothListViewItem
andListViewSubItem
implemented. \$\endgroup\$