我面对一个非常大的问题(对我而言)。我找不到任何解决方案。我的ListView中有四列:
ID = integer
Name = string
Response = boolean
Memory = mixed integer with string (1'000 KB)
在[ColumnClick]之后我可以排序(asc / desc)前3列“正常”,但是当我尝试排序第4列时,而不是
1 KB / 5 KB / 1'000 KB
我确实收到了这样的话:
1 KB / 1'000 KB / 5 KB
第四栏的印刷方式如下:
ListView1.Items(Count).SubItems.Add(FormatNumber(pMem, 0) & " KB")
我在想这个:
If e.Column.ToString = 3 Then
Dim final As Integer
For Each value In ListView1.Items
Replace(value.SubItems(3), "'", "")
Replace(value.SubItems(3), " KB", "")
final = value
Next
Else
...
然后以与ID相同的方式对整数进行排序,然后以某种方式将它们放回到ListView中。但我无法弄清楚如何。
以表格形式排序:
Private Sub ListView1_ColumnClick(sender As Object, e As ColumnClickEventArgs) Handles ListView1.ColumnClick
Dim ListViewSorter As New ListViewSorter
With ListViewSorter
.SortingOrder = 1
.ColumnIndex = e.Column
End With
ListView1.ListViewItemSorter = ListViewSorter
End Sub
我的ListViewSorter.vb
Public Class ListViewSorter
Implements IComparer
Private ColumnId As Integer
Private SortOrder As SortOrder
Private ItemComparer As CaseInsensitiveComparer
Public Sub New()
ColumnId = 0
SortOrder = 0
ItemComparer = New CaseInsensitiveComparer()
End Sub
Public Property ColumnIndex() As Integer
Get
Return ColumnId
End Get
Set(Value As Integer)
ColumnId = Value
End Set
End Property
Public Property SortingOrder() As SortOrder
Get
Return SortOrder
End Get
Set(Value As SortOrder)
SortOrder = Value
End Set
End Property
Public Function Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
Dim myResults As Integer
Dim strX As String = DirectCast(x, ListViewItem).SubItems(ColumnId).Text
Dim strY As String = DirectCast(y, ListViewItem).SubItems(ColumnId).Text
Dim num As Point
If Integer.TryParse(strX, num.X) And Integer.TryParse(strY, num.Y) Then
myResults = ItemComparer.Compare(num.X, num.Y)
Else
myResults = ItemComparer.Compare(strX, strY)
End If
If SortOrder = 1 Then
Return myResults
ElseIf SortOrder = 2 Then
Return -myResults
Else
Return 0
End If
End Function
End Class
答案 0 :(得分:2)
最佳解决方案是使用DataGridView
。使用DataSource
,而不是创建和添加ListViewItems
,然后ListViewSubItems
,您可以使用一行代码填充控件。它还使用类型化列,因此KBs或KG列会对数字进行排序。然后可以使用简单的linq表达式对DataSource
重新排序。
值得考虑在ColumnHeader
中添加“KB”标识,因此它不会在文本中反复重复,必须将其删除以进行排序。
由于ListView
只存储文本,您可以遇到其他问题:“9 KB”将排序高于“1000 KB”,因为那里没有整数 - 它们是数字。在许多情况下,您可以对包含数字的字符串使用NaturalSort
(“就像探险家”),但无论出于何种原因,它都不喜欢'
数字组分隔符。
这给我们留下了ListViewItemSorter
。您可能已经有一个用于排序第1列和第2列。需要更多逻辑来从KB列中提取实际数值以进行排序:
Public Class ListViewKBItemComparer
Implements IComparer
Private mySortFlipper As Int32 = 1
Public Property SortColumn As Int32 = 0
Public Sub New()
End Sub
Public Sub New(column As Int32, sort As SortOrder)
mySortFlipper = If(sort = SortOrder.Ascending, 1, -1)
SortColumn = column
End Sub
Public Function Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
Dim result As Int32
Dim lvX = CType(x, ListViewItem)
Dim lvY = CType(y, ListViewItem)
If SortColumn = 3 Then
result = KBCompare(lvX, lvY)
Else
result = String.Compare(lvX.SubItems(SortColumn).Text,
lvY.SubItems(SortColumn).Text)
End If
Return (result * mySortFlipper)
End Function
Private Function KBCompare(x As ListViewItem, y As ListViewItem) As Int32
' strip the text
Dim xs = x.SubItems(SortColumn).Text.Replace(" KB", "")
Dim ys = y.SubItems(SortColumn).Text.Replace(" KB", "")
' convert to decimal
Dim decX As Decimal = -1
Decimal.TryParse(xs, decX)
Dim decY As Decimal = -1
Decimal.TryParse(ys, decY)
' return comparison result
Return decX.CompareTo(decY)
End Function
End Class
我使用Decimal
以防某些字符串也包含分数。如果没有,只需将Decimal
更改为Int32
即可。
用法:
myLV.ListViewItemSorter = New ListViewKBItemComparer(e.Column, SortAsc)
myLV.Sort()
e.Column
是来自ColumnClick
事件的参数; SortAsc
是SortOrder
表示Asc或Desc。
答案 1 :(得分:0)
是的,您应该使用您给出的示例,在稍微调整一下后删除数组中的文本。
如果它是一个字符串数组,我怀疑它是,你应该使用你的替换方法删除撇号,但你应该在将它们添加到ListBox之前替换它们。
您可以通过以下方式执行此操作:
For Each value In FormatNumber
FormatNumber(count) = Replace(value, "'", "")
count +=1
Next
我猜测FormatNumber是一个字符串数组,所以你需要将它转换为整数。 为此,我只是将第一个回复中的示例复制到this question.
在上面的For循环之后添加以下代码行。
Dim intArray = Array.ConvertAll(FormatNumber, Function(str) Int32.Parse(str))
现在在将其分类到列表框后添加intArray的每个值,看看它是否有效。
答案 2 :(得分:0)
我遇到了同样的问题,似乎没有任何答案可行。最后我
做了一种将每个lv SubItem
转换为string array
,然后转换的排序
要排序到string
的值,然后将值转换为Integer
,
设置上升/下降方向,如果需要交换,则打包
从string array
到相对LV subitem
的每个项目。这里是
我用的代码。它适用于我的应用程序。
Private Sub SortStandings()
'Sorts Records by won/loss Percentage for Year
'Listview Items to be worked with
Dim LVItemX As ListViewItem
Dim LVItemY As ListViewItem
'String Copy of Value to Compare from List View Item
Dim Strx As String
Dim Stry As String
'Integer Value of Value to Compare From List (Cannot Cast LV Value directly to String
Dim XX As Integer
Dim YY As Integer
'Sort Direction Indicator
Dim J As Integer
Dim ITemX(ColLst.Pct) As String
Dim ItemY(ColLst.Pct) As String
Dim Altx As Integer
Dim Alty As Integer
'For each List View Item except the Last one
For x = 0 To lvDisplay.Items.Count - 2
LVItemX = lvDisplay.Items(x)
'Compare it to each lvItem below it
For y = x + 1 To lvDisplay.Items.Count - 1
LVItemY = lvDisplay.Items(y)
'Convert values to Sort to String (Cannot go directly to Integer
Strx = LVItemX.SubItems.Item(ColLst.Pct).Text
Stry = LVItemY.SubItems.Item(ColLst.Pct).Text
'Take Care of Possible Discrepancy in Format
If Strx = "" Then Strx = "0%"
If Stry = "" Then Stry = "0%"
'Convert Strings to Integer
XX = CInt(Microsoft.VisualBasic.Left(Strx, Len(Strx) - 1))
YY = CInt(Microsoft.VisualBasic.Left(Stry, Len(Stry) - 1))
'Set up a tie Breaker Based on as Different Column
Altx = CInt(LVItemX.SubItems.Item(ColLst.YW).Text)
Alty = CInt(LVItemY.SubItems.Item(ColLst.YW).Text)
'Set up Comparison for Descending ( Change > to < for Ascending )
J = 0
If XX < YY Then
J = -1
End If
If XX = YY And Altx < Alty Then
J = -1
End If
'rebuild Both LV Items in New Locations
If J = -1 Then
For n = 0 To ColLst.Pct
ITemX(n) = LVItemX.SubItems.Item(n).Text
ItemY(n) = LVItemY.SubItems.Item(n).Text
Next
For n = 0 To ColLst.Pct
LVItemX.SubItems.Item(n).Text = ItemY(n)
LVItemY.SubItems.Item(n).Text = ITemX(n)
Next
End If
Next
Next
End Sub