Patrick Thorpe Patrick Thorpe - 1 year ago 118 Question

Sorting a DataGridView by date column using a custom IComparer

I have a data grid view on a form with a date column and I would like to sort the column when a sort button is pressed.

Here is the code for the button click event:

Private Sub DateOfBirthSortButton_Click(sender As Object, e As EventArgs) Handles DateOfBirthSortButton.Click
PatientDataGridView.Sort(New DatabaseModule.DateComparer)
End Sub

And for the comparer:

Public outputFile As String = "C:\Users\Patrick\Desktop\outputTest.txt"

Public Class DateComparer
Implements IComparer

' Compare the two dates
Public Function Compare(ByVal rowX As Object, ByVal rowY As Object) As Integer Implements System.Collections.IComparer.Compare

'Get the date value from the collection of cells in the row
Dim dateX As String = rowX.Cells.Item(2).Value.ToString
Dim dateY As String = rowX.Cells.Item(2).Value.ToString

'Convert to a date
Dim x As Date = DateTime.ParseExact(dateX, "dd-MM-yyyy", Nothing)
Dim y As Date = DateTime.ParseExact(dateX, "dd-MM-yyyy", Nothing)

Dim cmpDate As Integer = Date.Compare(x, y)

Dim objWriter As New System.IO.StreamWriter(outputFile, True)

objWriter.WriteLine(dateX & " " & dateY & " " & cmpDate)

Return cmpDate

End Function
End Class

I have added code which puts the results from the comparer into a text file so that I could see the results of each comparison.

However, when the button is pressed, the comparer only compares the same row against itself, in a seemingly random order, sometimes multiple times.

Here is the initial order (I've given the people numbers to show which order they should sort into):

Initial ordering

And the resultant order after the sort button is pressed:

Resultant ordering

And the comparisons recorded in the text file:

Text file results

If anyone could explain to me how I can fix my problem I would be very grateful, thanks :)

Answer Source

The short answer is that you have a copy-paste error:

Dim dateX As String = rowX.Cells.Item(2).Value.ToString
'  note that DateY is also getting from RowX
'   should be         rowY
Dim dateY As String = rowX.Cells.Item(2).Value.ToString

You should also turn on Option Strict, rowX and rowY are passed as Object but you are using them as DataGridViewRows without casting them:

Public Function Compare(X As Object, Y As Object) ...
    Dim rowX = TryCast(X, DataGridViewRow)

If/when you do need a custom sorter, you might want write it to allow the column and sort order in the constructor so it can work with more than just one column and be able to flip from Ascending to Descending and back. Example:

' specify the column to sort, and the order:
dgv1.Sort(New DGVPatientSorter(2, thisOrder))

Since it will allow you to use a Sorter, the data must not be bound. Too bad. But, if you define that column as a Date type, it will sort dates just fine:

dgv1.Columns(2).ValueType = GetType(DateTime)

Then sorting:

dgv1.Sort(dgv1.Columns(2), ListSortDirection.Ascending)