Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: Krähne en 18 Mayo 2011, 08:54 am



Título: ¿Ordenar items en ListView de la Columna seleccionada?
Publicado por: Krähne en 18 Mayo 2011, 08:54 am
Hola... no haré mucha presentación, iré al grano: (Ojo, ya realicé esta misma pregunta en la MSDN (http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/a282b5ab-40d3-413a-868e-ae968b88c8b0), a ver quién me da una mano antes :xD).

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:

Código
  1.        internal static string GetDllSize(long Bytes)
  2.        {
  3.            const int Scale = 1024;
  4.            string[] Sizes = new string[] { "GB", "MB", "KB", "Bytes" };
  5.            long Max = (long)Math.Pow(Scale, Sizes.Length - 1);
  6.  
  7.            foreach (string Order in Sizes)
  8.            {
  9.                if (Bytes > Max)
  10.                    return string.Format("{0:##.##} {1}", decimal.Divide(Bytes, Max), Order);
  11.                Max /= Scale;
  12.            }
  13.            return "0 Bytes";
  14.        }

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 (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:

Código
  1. Private Declare Function LockWindowUpdate Lib "user32" _
  2.        (ByVal hWndLock As Long) As Long
  3.  
  4. Private Declare Function GetTickCount Lib "kernel32" () As Long
  5.  
  6. Private Sub Form_Load()
  7.    With ListView1
  8.  
  9.        ' Add three columns to the list - one for each data type.
  10.        ' Note that the data type is set in the column header's
  11.        ' tag in each case
  12.  
  13.        .ColumnHeaders.Add(, , "String").Tag = "STRING"
  14.        .ColumnHeaders.Add(, , "Number").Tag = "NUMBER"
  15.        .ColumnHeaders.Add(, , "Date").Tag = "DATE"
  16.  
  17.        ' Set the column alignment - has no bearing on the sorts.
  18.  
  19.        .ColumnHeaders(1).Alignment = lvwColumnLeft
  20.        .ColumnHeaders(2).Alignment = lvwColumnRight
  21.        .ColumnHeaders(3).Alignment = lvwColumnCenter
  22.  
  23.        ' Populate the list with data
  24.  
  25.        Dim l As Long
  26.        Dim dblRnd As Double
  27.        Dim dteRnd As Date
  28.        With .ListItems
  29.            For l = 1 To 1000
  30.                With .Add(, , "ListItem " & Format(l, "0000"))
  31.                    dblRnd = (Rnd() * 10000) - 5000
  32.                    dteRnd = (Rnd() * 1000) + Date
  33.                    .ListSubItems.Add , , Format(dblRnd, "0.00")
  34.                    .ListSubItems.Add , , Format(dteRnd, _
  35.                                                   "dd/mm/yyyy")
  36.                End With
  37.            Next l
  38.        End With
  39.  
  40.    End With
  41. End Sub
  42.  
  43. Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _
  44.                                    MSComctlLib.ColumnHeader)
  45.  
  46.    On Error Resume Next
  47.  
  48.    ' Record the starting CPU time (milliseconds since boot-up)
  49.  
  50.    Dim lngStart As Long
  51.    lngStart = GetTickCount
  52.  
  53.    ' Commence sorting
  54.  
  55.    With ListView1
  56.  
  57.        ' Display the hourglass cursor whilst sorting
  58.  
  59.        Dim lngCursor As Long
  60.        lngCursor = .MousePointer
  61.        .MousePointer = vbHourglass
  62.  
  63.        ' Prevent the ListView control from updating on screen -
  64.        ' this is to hide the changes being made to the listitems
  65.        ' and also to speed up the sort
  66.  
  67.        LockWindowUpdate .hWnd
  68.  
  69.        ' Check the data type of the column being sorted,
  70.        ' and act accordingly
  71.  
  72.        Dim l As Long
  73.        Dim strFormat As String
  74.        Dim strData() As String
  75.  
  76.        Dim lngIndex As Long
  77.        lngIndex = ColumnHeader.Index - 1
  78.  
  79.        Select Case UCase$(ColumnHeader.Tag)
  80.        Case "DATE"
  81.  
  82.            ' Sort by date.
  83.  
  84.            strFormat = "YYYYMMDDHhNnSs"
  85.  
  86.            ' Loop through the values in this column. Re-format
  87.            ' the dates so as they can be sorted alphabetically,
  88.            ' having already stored their visible values in the
  89.            ' tag, along with the tag's original value
  90.  
  91.            With .ListItems
  92.                If (lngIndex > 0) Then
  93.                    For l = 1 To .Count
  94.                        With .Item(l).ListSubItems(lngIndex)
  95.                            .Tag = .Text & Chr$(0) & .Tag
  96.                            If IsDate(.Text) Then
  97.                                .Text = Format(CDate(.Text), _
  98.                                                    strFormat)
  99.                            Else
  100.                                .Text = ""
  101.                            End If
  102.                        End With
  103.                    Next l
  104.                Else
  105.                    For l = 1 To .Count
  106.                        With .Item(l)
  107.                            .Tag = .Text & Chr$(0) & .Tag
  108.                            If IsDate(.Text) Then
  109.                                .Text = Format(CDate(.Text), _
  110.                                                    strFormat)
  111.                            Else
  112.                                .Text = ""
  113.                            End If
  114.                        End With
  115.                    Next l
  116.                End If
  117.            End With
  118.  
  119.            ' Sort the list alphabetically by this column
  120.  
  121.            .SortOrder = (.SortOrder + 1) Mod 2
  122.            .SortKey = ColumnHeader.Index - 1
  123.            .Sorted = True
  124.  
  125.            ' Restore the previous values to the 'cells' in this
  126.            ' column of the list from the tags, and also restore
  127.            ' the tags to their original values
  128.  
  129.            With .ListItems
  130.                If (lngIndex > 0) Then
  131.                    For l = 1 To .Count
  132.                        With .Item(l).ListSubItems(lngIndex)
  133.                            strData = Split(.Tag, Chr$(0))
  134.                            .Text = strData(0)
  135.                            .Tag = strData(1)
  136.                        End With
  137.                    Next l
  138.                Else
  139.                    For l = 1 To .Count
  140.                        With .Item(l)
  141.                            strData = Split(.Tag, Chr$(0))
  142.                            .Text = strData(0)
  143.                            .Tag = strData(1)
  144.                        End With
  145.                    Next l
  146.                End If
  147.            End With
  148.  
  149.        Case "NUMBER"
  150.  
  151.            ' Sort Numerically
  152.  
  153.            strFormat = String(30, "0") & "." & String(30, "0")
  154.  
  155.            ' Loop through the values in this column. Re-format the values so as they
  156.            ' can be sorted alphabetically, having already stored their visible
  157.            ' values in the tag, along with the tag's original value
  158.  
  159.            With .ListItems
  160.                If (lngIndex > 0) Then
  161.                    For l = 1 To .Count
  162.                        With .Item(l).ListSubItems(lngIndex)
  163.                            .Tag = .Text & Chr$(0) & .Tag
  164.                            If IsNumeric(.Text) Then
  165.                                If CDbl(.Text) >= 0 Then
  166.                                    .Text = Format(CDbl(.Text), _
  167.                                        strFormat)
  168.                                Else
  169.                                    .Text = "&" & InvNumber( _
  170.                                        Format(0 - CDbl(.Text), _
  171.                                        strFormat))
  172.                                End If
  173.                            Else
  174.                                .Text = ""
  175.                            End If
  176.                        End With
  177.                    Next l
  178.                Else
  179.                    For l = 1 To .Count
  180.                        With .Item(l)
  181.                            .Tag = .Text & Chr$(0) & .Tag
  182.                            If IsNumeric(.Text) Then
  183.                                If CDbl(.Text) >= 0 Then
  184.                                    .Text = Format(CDbl(.Text), _
  185.                                        strFormat)
  186.                                Else
  187.                                    .Text = "&" & InvNumber( _
  188.                                        Format(0 - CDbl(.Text), _
  189.                                        strFormat))
  190.                                End If
  191.                            Else
  192.                                .Text = ""
  193.                            End If
  194.                        End With
  195.                    Next l
  196.                End If
  197.            End With
  198.  
  199.            ' Sort the list alphabetically by this column
  200.  
  201.            .SortOrder = (.SortOrder + 1) Mod 2
  202.            .SortKey = ColumnHeader.Index - 1
  203.            .Sorted = True
  204.  
  205.            ' Restore the previous values to the 'cells' in this
  206.            ' column of the list from the tags, and also restore
  207.            ' the tags to their original values
  208.  
  209.            With .ListItems
  210.                If (lngIndex > 0) Then
  211.                    For l = 1 To .Count
  212.                        With .Item(l).ListSubItems(lngIndex)
  213.                            strData = Split(.Tag, Chr$(0))
  214.                            .Text = strData(0)
  215.                            .Tag = strData(1)
  216.                        End With
  217.                    Next l
  218.                Else
  219.                    For l = 1 To .Count
  220.                        With .Item(l)
  221.                            strData = Split(.Tag, Chr$(0))
  222.                            .Text = strData(0)
  223.                            .Tag = strData(1)
  224.                        End With
  225.                    Next l
  226.                End If
  227.            End With
  228.  
  229.        Case Else   ' Assume sort by string
  230.  
  231.            ' Sort alphabetically. This is the only sort provided
  232.            ' by the MS ListView control (at this time), and as
  233.            ' such we don't really need to do much here
  234.  
  235.            .SortOrder = (.SortOrder + 1) Mod 2
  236.            .SortKey = ColumnHeader.Index - 1
  237.            .Sorted = True
  238.  
  239.        End Select
  240.  
  241.        ' Unlock the list window so that the OCX can update it
  242.  
  243.        LockWindowUpdate 0&
  244.  
  245.        ' Restore the previous cursor
  246.  
  247.        .MousePointer = lngCursor
  248.  
  249.    End With
  250.  
  251.    ' Report time elapsed, in milliseconds
  252.  
  253.    MsgBox "Time Elapsed = " & GetTickCount - lngStart & "ms"
  254.  
  255. End Sub
  256.  
  257. '****************************************************************
  258. ' InvNumber
  259. ' Function used to enable negative numbers to be sorted
  260. ' alphabetically by switching the characters
  261. '----------------------------------------------------------------
  262.  
  263. Private Function InvNumber(ByVal Number As String) As String
  264.    Static i As Integer
  265.    For i = 1 To Len(Number)
  266.        Select Case Mid$(Number, i, 1)
  267.        Case "-": Mid$(Number, i, 1) = " "
  268.        Case "0": Mid$(Number, i, 1) = "9"
  269.        Case "1": Mid$(Number, i, 1) = "8"
  270.        Case "2": Mid$(Number, i, 1) = "7"
  271.        Case "3": Mid$(Number, i, 1) = "6"
  272.        Case "4": Mid$(Number, i, 1) = "5"
  273.        Case "5": Mid$(Number, i, 1) = "4"
  274.        Case "6": Mid$(Number, i, 1) = "3"
  275.        Case "7": Mid$(Number, i, 1) = "2"
  276.        Case "8": Mid$(Number, i, 1) = "1"
  277.        Case "9": Mid$(Number, i, 1) = "0"
  278.        End Select
  279.    Next
  280.    InvNumber = Number
  281. End Function

Pues bien, también he leído éste (http://support.microsoft.com/kb/319401) 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ß.


Título: Re: ¿Ordenar items en ListView de la Columna seleccionada?
Publicado por: seba123neo en 19 Mayo 2011, 04:04 am
ni te orientes con el de visual basic 6, busca ejemplos para C# o visual basic .NET que hay varios de esto en internet, yo use un ejemplo que hay por ahi que utiliza la interface IComparer que compara lo que sea, te ordena correctamente cualquier tipo de datos, string, numero, fechas..etc.

Make a ListView control sort using the column you click in VB .NET (http://www.vb-helper.com/howto_net_listview_sort_clicked_column.html)

pero hay muchos mas en internet, BUSCA....

saludos.



Título: Re: ¿Ordenar items en ListView de la Columna seleccionada?
Publicado por: Krähne en 19 Mayo 2011, 20:40 pm
ni te orientes con el de visual basic 6, busca ejemplos para C# o visual basic .NET que hay varios de esto en internet, yo use un ejemplo que hay por ahi que utiliza la interface IComparer que compara lo que sea, te ordena correctamente cualquier tipo de datos, string, numero, fechas..etc.

Make a ListView control sort using the column you click in VB .NET (http://www.vb-helper.com/howto_net_listview_sort_clicked_column.html)

pero hay muchos mas en internet, BUSCA....

saludos.

Pues, porque estoy harto de buscar es que vine a preguntar.

Y sí, así es, iComparer es de lo mejor que hay para hacer ordenes y comparaciones, el problema es que ignoro su uso, y el soporte que da microsoft sencillamente APESTA.

De todos modos gracias por el ejemplo, le echaré un vistaso.