簡體   English   中英

vb.net在ListView中排序混合的整數和字符串列

[英]vb.net sorting mixed integer and string column in ListView

我面對着一個非常大的問題(對我來說)。 我找不到任何解決方案。 我的ListView中有四列:

ID = integer
Name = string
Response = boolean
Memory = mixed integer with string (1'000 KB)

在[ColumnClick]之后,我可以“正常”對前3列進行排序(asc / desc),但是當我嘗試對第四列進行排序時,而不是

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

最佳解決方案是使用DataGridView 使用DataSource ,而不是先創建和添加ListViewItems ,然后再創建ListViewSubItems ,您可以用一行代碼填充控件。 它還使用類型化的列,因此KB或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.ColumnColumnClick事件的參數; SortAsc是用於表示Asc或Desc的SortOrder

是的,您應該使用給定的示例,在進行一些調整之后,刪除數組中的文本。

如果是我懷疑是的字符串數組,則應使用replace方法刪除撇號,但是在將其添加到ListBox之前應替換它們。

您可以通過以下方式做到這一點:

For Each value In FormatNumber
        FormatNumber(count) = Replace(value, "'", "")
        count +=1
Next

我猜想FormatNumber是一個字符串數組,因此您需要將其轉換為整數。 為此,我只是將示例從第一個回答中復制到此問題。

在上面的For循環之后添加以下代碼行。

Dim intArray = Array.ConvertAll(FormatNumber, Function(str) Int32.Parse(str))

現在,將intArray的每個值排序后添加到列表框中,看是否可行。

我遇到了同樣的問題,似乎沒有答案。 最后,我進行了排序,將每個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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM