I\'ve got a DataGridView control in a Windows forms application. There are four columns with string data and three with DateTime data. I\'m adding the rows programmatically
If you're adding rows dynamically I must assume the DataGridView is not Databound. In this case why don't you check for nulls when populating the correspondent row cells and instantiate some kind of dummy date (some funny date in the past so that it's clear that it was a null - maybe also specify that it's a default value) so that when it comes to sorting it's ll good.
If this ain't good - what about creating your own DataGridView exactly the same as the built-in one (using inheritance) BUT overriding the sorting method to ignore nulls?
Updated Answer: After looking at your posted answer, I see that you're checking for DBNull.Value in the cells. That may be the source of your problem since DBNull.Value can't be cast to a DateTime. If you're programmatically adding the rows, try replacing DBNull.Value with null (Nothing).
Original Answer: Try doing this for each column that holds DateTime data, preferably before any data is loaded:
myDateTimeColumn.ValueType = GetType(DateTime)
According to MSDN, the ValueType property is "used when filtering or sorting the columns with respect to the contents of their cells." So I would be sure to set it for any column that allows sorting.
With this property set, the grid can be sorted on a column that has nulls and will force inserted/updated cells to be converted to DateTime.
An easy solution is to add a "tonull" function, which you run the e.cellvalue1 and 2 through each time a comparison is made. If the value is "" then the value of the cell will be changed to 01/01/1001 if you want null values to appear first on the sort or 01/01/3001 or something ridiculously high if you want them to appear last on the sort.
Private Sub dgvTable_SortCompare(ByVal sender As Object, ByVal e As DataGridViewSortCompareEventArgs) Handles dgvTable.SortCompare
If e.Column.Index = 4 Then
e.SortResult = System.DateTime.Compare(todatenull(e.CellValue1), todatenull(e.CellValue2))
End If
e.Handled = True
End Sub
Function todatenull(ByVal cellvalue)
If cellvalue = "" Then
Return "01/01/1001"
Else
Return cellvalue
End If
End Function
Here's the solution I came up with. The DataGridView raises a SortCompare event that you can use to input custom sorting. I'm handling that event and making null values sort out higher than non-null values (you could just as easily make nulls lower than non-nulls). Here's the VB code. I'm assuming every cell value is IComparable (if not it will be handled by the normal error handling logic.)
Try
If e.CellValue1 Is Nothing OrElse e.CellValue1.Equals(DBNull.Value) Then
If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) Then
e.SortResult = 0
Else
e.SortResult = 1
End If
Else
If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) Then
e.SortResult = -1
Else
e.SortResult = DirectCast(e.CellValue1, IComparable).CompareTo(DirectCast(e.CellValue2, IComparable))
End If
End If
e.Handled = True
Catch ex As Exception
HandleError("Error sorting result grid values", ex)
Close()
End Try
If anybody has any improvements on this please feel free to post them.
Just to add some code to this question... I did the following to get sorting to work correctly for DateTime (and other non-string types) in the presence of nulls:
public MyFormCTor() {
...
m_dataGridView.SortCompare += MySortCompare;
...
}
...
static void MySortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
if (e.CellValue1 == e.CellValue2)
{
e.SortResult = 0;
return;
}
if (e.CellValue1 == null)
{
e.SortResult = -1;
return;
}
if (e.CellValue2 == null)
{
e.SortResult = 1;
return;
}
e.SortResult = ((IComparable)e.CellValue1).CompareTo(e.CellValue2);
}