none
¿Ordenar items en ListView de la Columna seleccionada? RRS feed

  • Pregunta

  • Buenas... soy un poco nuevo en esto de la msdn, así que espero me tengan algo de paciencia jeje.

      Tengo un ListView con X items, cada item contiene X información, el ListView tiene 4 columnas y estas son:

    Nombre | Tamaño | Estado | Atributos

    En el cual cada columna guarda la información referente a un archivo de texto o .ini seleccionado.

    El problema reside al momento de querer ordenar los items de cada columna al hacer click en ellos, y pasa lo siguiente:

    Al momento de hacer click en cualquier columna excepto en la de "Tamaño", los items cogen su orden alfabético de manera correcta, pero... si lo hago con la columna "Tamaño" tan sólo se invierte su orden, entonces lo que quisiera es que, al momento de darle click, se ordenara según su peso.

    El subitem en esa columna contendrá información en este formato: ##.## Bytes, ##.## KB, ##.## MB y ##.## GB. Donde # equivale al tamaño del item.

    La manera para obtener el tamaño de cada item, se hace con esta función:

      internal static string GetDllSize(long Bytes)
      {
       const int Scale = 1024;
       string[] Sizes = new string[] { "GB", "MB", "KB", "Bytes" };
       long Max = (long)Math.Pow(Scale, Sizes.Length - 1);
    
       foreach (string Order in Sizes)
       {
        if (Bytes > Max)
         return string.Format("{0:##.##} {1}", decimal.Divide(Bytes, Max), Order);
        Max /= Scale;
       }
       return "0 Bytes";
      }

    Entonces, como decía arriba, quisiera saber cómo ordenar estos items al hacer click en la columna, (eh si... ya sé que con el evento column_click), pues... como dije anteriormente ya lo he realizado sin problemas con los demás datos, que tan sólo son strings.

    Por si sirve de algo, encontré un código en Visual Basic 6 (Geshi VB.NET) (El cuál aún no me he dispuesto a convertir a C# por temor a perder tiempo fracasando en su conversión), que ordena sin problemas números, fechas y cadenas de texto, de éste me quiero guiar, pero no sé si haya una manera más eficiente en C#.

    El código es el siguiente:

    Option Explicit
    
    Private Declare Function LockWindowUpdate Lib "user32" _
     (ByVal hWndLock As Long) As Long
    
    Private Declare Function GetTickCount Lib "kernel32" () As Long
    
    Private Sub Form_Load()
     With ListView1
     
     ' Add three columns to the list - one for each data type.
     ' Note that the data type is set in the column header's
     ' tag in each case
     
     .ColumnHeaders.Add(, , "String").Tag = "STRING"
     .ColumnHeaders.Add(, , "Number").Tag = "NUMBER"
     .ColumnHeaders.Add(, , "Date").Tag = "DATE"
     
     ' Set the column alignment - has no bearing on the sorts.
     
     .ColumnHeaders(1).Alignment = lvwColumnLeft
     .ColumnHeaders(2).Alignment = lvwColumnRight
     .ColumnHeaders(3).Alignment = lvwColumnCenter
     
     ' Populate the list with data
     
     Dim l As Long
     Dim dblRnd As Double
     Dim dteRnd As Date
     With .ListItems
     For l = 1 To 1000
     With .Add(, , "ListItem " & Format(l, "0000"))
     dblRnd = (Rnd() * 10000) - 5000
     dteRnd = (Rnd() * 1000) + Date
     .ListSubItems.Add , , Format(dblRnd, "0.00")
     .ListSubItems.Add , , Format(dteRnd, _
     "dd/mm/yyyy")
     End With
     Next l
     End With
     
     End With
    End Sub
    
    
    Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
     MSComctlLib.ColumnHeader)
    
     On Error Resume Next
     
     ' Record the starting CPU time (milliseconds since boot-up)
     
     Dim lngStart As Long
     lngStart = GetTickCount
     
     ' Commence sorting
     
     With ListView1
     
     ' Display the hourglass cursor whilst sorting
     
     Dim lngCursor As Long
     lngCursor = .MousePointer
     .MousePointer = vbHourglass
     
     ' Prevent the ListView control from updating on screen -
     ' this is to hide the changes being made to the listitems
     ' and also to speed up the sort
     
     LockWindowUpdate .hWnd
     
     ' Check the data type of the column being sorted,
     ' and act accordingly
     
     Dim l As Long
     Dim strFormat As String
     Dim strData() As String
     
     Dim lngIndex As Long
     lngIndex = ColumnHeader.Index - 1
     
     Select Case UCase$(ColumnHeader.Tag)
     Case "DATE"
     
     ' Sort by date.
     
     strFormat = "YYYYMMDDHhNnSs"
     
     ' Loop through the values in this column. Re-format
     ' the dates so as they can be sorted alphabetically,
     ' having already stored their visible values in the
     ' tag, along with the tag's original value
     
     With .ListItems
     If (lngIndex > 0) Then
     For l = 1 To .Count
     With .Item(l).ListSubItems(lngIndex)
     .Tag = .Text & Chr$(0) & .Tag
     If IsDate(.Text) Then
     .Text = Format(CDate(.Text), _
     strFormat)
     Else
     .Text = ""
     End If
     End With
     Next l
     Else
     For l = 1 To .Count
     With .Item(l)
     .Tag = .Text & Chr$(0) & .Tag
     If IsDate(.Text) Then
     .Text = Format(CDate(.Text), _
     strFormat)
     Else
     .Text = ""
     End If
     End With
     Next l
     End If
     End With
     
     ' Sort the list alphabetically by this column
     
     .SortOrder = (.SortOrder + 1) Mod 2
     .SortKey = ColumnHeader.Index - 1
     .Sorted = True
     
     ' Restore the previous values to the 'cells' in this
     ' column of the list from the tags, and also restore
     ' the tags to their original values
     
     With .ListItems
     If (lngIndex > 0) Then
     For l = 1 To .Count
     With .Item(l).ListSubItems(lngIndex)
     strData = Split(.Tag, Chr$(0))
     .Text = strData(0)
     .Tag = strData(1)
     End With
     Next l
     Else
     For l = 1 To .Count
     With .Item(l)
     strData = Split(.Tag, Chr$(0))
     .Text = strData(0)
     .Tag = strData(1)
     End With
     Next l
     End If
     End With
     
     Case "NUMBER"
     
     ' Sort Numerically
     
     strFormat = String(30, "0") & "." & String(30, "0")
     
     ' Loop through the values in this column. Re-format the values so as they
     ' can be sorted alphabetically, having already stored their visible
     ' values in the tag, along with the tag's original value
     
     With .ListItems
     If (lngIndex > 0) Then
     For l = 1 To .Count
     With .Item(l).ListSubItems(lngIndex)
     .Tag = .Text & Chr$(0) & .Tag
     If IsNumeric(.Text) Then
     If CDbl(.Text) >= 0 Then
     .Text = Format(CDbl(.Text), _
     strFormat)
     Else
     .Text = "&" & InvNumber( _
     Format(0 - CDbl(.Text), _
     strFormat))
     End If
     Else
     .Text = ""
     End If
     End With
     Next l
     Else
     For l = 1 To .Count
     With .Item(l)
     .Tag = .Text & Chr$(0) & .Tag
     If IsNumeric(.Text) Then
     If CDbl(.Text) >= 0 Then
     .Text = Format(CDbl(.Text), _
     strFormat)
     Else
     .Text = "&" & InvNumber( _
     Format(0 - CDbl(.Text), _
     strFormat))
     End If
     Else
     .Text = ""
     End If
     End With
     Next l
     End If
     End With
     
     ' Sort the list alphabetically by this column
     
     .SortOrder = (.SortOrder + 1) Mod 2
     .SortKey = ColumnHeader.Index - 1
     .Sorted = True
     
     ' Restore the previous values to the 'cells' in this
     ' column of the list from the tags, and also restore
     ' the tags to their original values
     
     With .ListItems
     If (lngIndex > 0) Then
     For l = 1 To .Count
     With .Item(l).ListSubItems(lngIndex)
     strData = Split(.Tag, Chr$(0))
     .Text = strData(0)
     .Tag = strData(1)
     End With
     Next l
     Else
     For l = 1 To .Count
     With .Item(l)
     strData = Split(.Tag, Chr$(0))
     .Text = strData(0)
     .Tag = strData(1)
     End With
     Next l
     End If
     End With
     
     Case Else ' Assume sort by string
     
     ' Sort alphabetically. This is the only sort provided
     ' by the MS ListView control (at this time), and as
     ' such we don't really need to do much here
     
     .SortOrder = (.SortOrder + 1) Mod 2
     .SortKey = ColumnHeader.Index - 1
     .Sorted = True
     
     End Select
     
     ' Unlock the list window so that the OCX can update it
     
     LockWindowUpdate 0&
     
     ' Restore the previous cursor
     
     .MousePointer = lngCursor
     
     End With
     
     ' Report time elapsed, in milliseconds
     
     MsgBox "Time Elapsed = " & GetTickCount - lngStart & "ms"
     
    End Sub
    
    Private Function InvNumber(ByVal Number As String) As String
     Static i As Integer
     For i = 1 To Len(Number)
     Select Case Mid$(Number, i, 1)
     Case "-": Mid$(Number, i, 1) = " "
     Case "0": Mid$(Number, i, 1) = "9"
     Case "1": Mid$(Number, i, 1) = "8"
     Case "2": Mid$(Number, i, 1) = "7"
     Case "3": Mid$(Number, i, 1) = "6"
     Case "4": Mid$(Number, i, 1) = "5"
     Case "5": Mid$(Number, i, 1) = "4"
     Case "6": Mid$(Number, i, 1) = "3"
     Case "7": Mid$(Number, i, 1) = "2"
     Case "8": Mid$(Number, i, 1) = "1"
     Case "9": Mid$(Number, i, 1) = "0"
     End Select
     Next
     InvNumber = Number
    End Function
    

    Pues bien, también he leído éste artículo de la msdn, pero... nunca había manejado el tema de iComparer, por tal ando un poco perdido en él.


    Si alguien pudiera echarme una mano, o al menos darme información sobre iComparer (un pequeño manual, o algo que me pueda servir para guiarme) se lo agradecería.

     

    Gruß.


    miércoles, 18 de mayo de 2011 4:55

Respuestas

Todas las respuestas