1

I have a two-column ListView linked to a Datapager. The ListView lists all files of a particular type in a particular directory, so the data source is an ArrayList of type FileInfo. Consequently, I had to create a Comparer class to use in the ArrayList.Sort method.

FileInfoComparer.vb:

Imports System.IO

Friend Class FileInfoDateComparer
 Implements IComparer

 Public Overridable Overloads Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
  Dim oX As FileInfo = CType(x, FileInfo)
  Dim oY As FileInfo = CType(y, FileInfo)
  Return oX.LastWriteTime.CompareTo(oY.LastWriteTime)
 End Function
End Class

Friend Class FileInfoNameComparer
 Implements IComparer

 Public Overridable Overloads Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
  Dim oX As FileInfo = CType(x, FileInfo)
  Dim oY As FileInfo = CType(y, FileInfo)
  Return oX.Name.CompareTo(oY.Name)
 End Function
End Class

GenerateSortedArray sub:

 Private Sub GenerateSortedArray(ByVal SortColumn As String, ByVal SortDirection As String)
  Dim dirInfo As New DirectoryInfo(Server.MapPath(AppSettings.Item("ContentDir")))
  Dim FileArrayList As New ArrayList(dirInfo.GetFiles("*.msg", SearchOption.TopDirectoryOnly))

  With FileArrayList
   .TrimToSize()
   Select Case SortColumn
    Case "Name"
     .Sort(New FileInfoNameComparer)
    Case Else
     .Sort(New FileInfoDateComparer)
   End Select
  End With

ListView_Sorting:

  Session("SortColumn") = e.SortExpression
  Session("SortDirection") = e.SortDirection

  Call GenerateSortedArray(e.SortExpression, DBNull.Value.ToString)

All this works well, however, I don't know how to reverse the sort. As you can see from the code, I've determined the Sort Direction, but I don't know how to use it to reverse the sort.

Any thoughts?

David
  • 19,389
  • 12
  • 63
  • 87
CJM
  • 11,908
  • 20
  • 77
  • 115
  • 3 excellent and almost identical solutions, and simple enough that even I could understand. Apologies to Rubens and Scott - I wish I could have given you a fair share of the spoils. – CJM Oct 07 '09 at 16:53
  • Thinking further, I really should roll the two comparer classes into one and pass on the column name as well... – CJM Oct 07 '09 at 16:55

3 Answers3

1

Have you Comparer classes include a Boolean member variable named something like SortAscending, and allow this value to be specified through the constructor.

For example, your FileInfoDateComparer class would look like the following (untested) code:

Class FileInfoDateComparer
 Implements IComparer

  Private _SortAscending As Boolean = True

  Public Sub New(sortAscending As Boolean)
    _SortAscending = sortAscending
  End Sub

  ...
End Class

With that in place all that remains is to "swap" the oX and oY values before calling CompareTo IF SortAscending = False.

Public Overridable Overloads Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
  Dim oX As FileInfo = CType(x, FileInfo)
  Dim oY As FileInfo = CType(y, FileInfo)

  If _SortAscending = False Then
    Dim temp As FileInfo = oX
    oX = oY
    oY = temp
  End If

  Return oX.LastWriteTime.CompareTo(oY.LastWriteTime)
End Function

That oughta do it! FYI, the above code was entered off the cuff, so there may be a syntax error in there, but the concept is sound - I've used it many times myself in past projects.

One final comment - if you are using .NET 3.5+ you can use LINQ to Objects syntax instead of having to create your own Comparer class, if you so desire...

Happy Programming...

Scott Mitchell
  • 8,659
  • 3
  • 55
  • 71
  • Ditto my comments to Ruben, I came across a clear Comparer example that made sense. LINQ is a complete unknown at the moment, though obviously is on my To-Do list (along with so much else!). – CJM Oct 07 '09 at 16:58
  • CJM, check out this article for a gentle introduction into LINQ (with VB and C# examples): http://www.4guysfromrolla.com/articles/021109-1.aspx FYI, here's how easy and terse LINQ makes everything: dirInfo.GetFiles("*.msg", SearchOption.TopDirectoryOnly).OrderBy(Function(f) f.LastWriteTime) – Scott Mitchell Oct 10 '09 at 23:19
1

You can send SortDirectory through your FileInfoDateComparer; receiving an "DESC" value you can multiply return value by -1;

// sorry, C# version:

class FileInfoDateComparer
{
    private bool ascendingOrder = true;
    public FileInfoDateComparer(bool ascendingOrder)
    {
        this.sortOrder = sortOrder;
    }

    ... int Compare(object x, object y)
    {
        //...
        return
            oX.LastWriteTime.CompareTo(oY.LastWriteTime) * 
            (ascendingOrder ? 1: -1);
    }

}

You said nothing about your framework version, but think about using Reverse() Linq extension method.

Rubens Farias
  • 57,174
  • 8
  • 131
  • 162
  • I'm using 3.5 so LINQ is on the cards, but it's just one step further into the unknown at the moment - but I appreciate your suggestion. – CJM Oct 07 '09 at 16:56
1

I have usually done something like this:

Friend Class FileInfoDateComparer
 Implements IComparer

    Private _sortOrder As System.Windows.Forms.SortOrder

    Public Sub New(ByVal sortOrder As System.Windows.Forms.SortOrder)
        _sortOrder = sortOrder
    End Sub

    Public Overridable Overloads Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
       Dim oX As FileInfo = CType(x, FileInfo)
       Dim oY As FileInfo = CType(y, FileInfo)
       Dim result As Integer = oX.LastWriteTime.CompareTo(oY.LastWriteTime)
       If _sortOrder = System.Windows.Forms.SortOrder.Descending Then
           ' we want the reverse sort order, so we "reverse" the result '
           result = result * -1
       End If
       Return result
 End Function
End Class

If you don't want to use the System.Windows.Forms.SortOrder, you can roll your own SortOrder enum. I usually prefer enums over booleans since you will get a clear statement in your code what the value means. Compare these two:

Dim comparer As New FileInfoDateComparer(True)
Dim comparer As New FileInfoDateComparer(SortOrder.Descending)
Fredrik Mörk
  • 155,851
  • 29
  • 291
  • 343
  • I actually used SqlClient.SortOrder (it is a web app after all!), but you get the big prize for suggesting enumeration. Simple but neat. – CJM Oct 07 '09 at 16:52