.net DataGridView排序,DateTime列中为空

.net DataGridView排序,DateTime列中为空,.net,winforms,datagridview,.net,Winforms,Datagridview,我在Windows窗体应用程序中有一个DataGridView控件。有四列包含字符串数据,三列包含日期时间数据。我使用rows.Add()方法以编程方式添加行。所有列都将SortMode设置为Automatic。单击列标题进行排序只起作用,只有一个DateTime列有一些空值。当用户单击该列的标题时,它抛出ArgumentException:对象的类型必须为DateTime 我知道解决这个问题的困难方法:将所有SortModes设置为NotSortable,处理ColumnHeaderMouse

我在Windows窗体应用程序中有一个DataGridView控件。有四列包含字符串数据,三列包含日期时间数据。我使用rows.Add()方法以编程方式添加行。所有列都将SortMode设置为Automatic。单击列标题进行排序只起作用,只有一个DateTime列有一些空值。当用户单击该列的标题时,它抛出ArgumentException:对象的类型必须为DateTime

我知道解决这个问题的困难方法:将所有SortModes设置为NotSortable,处理ColumnHeaderMouseClick事件并手动对整个事件进行排序。我在寻找简单的方法


是否有一个属性或我可以设置的东西,或者其他相对简单的方法来允许此列使用空值进行排序?

如果要动态添加行,我必须假设DataGridView不是数据绑定的。 在这种情况下,为什么不在填充对应的行单元格时检查空值,并实例化某种类型的伪日期(过去的一些有趣的日期,这样就可以清楚地知道它是空值-也可以指定它是默认值),以便在排序时使用它


如果这不好-如何创建与内置DataGridView完全相同的DataGridView(使用继承)覆盖排序方法以忽略空值?

更新的答案: 在查看您发布的答案后,我看到您正在检查单元格中的DBNull.Value。这可能是问题的根源,因为DBNull.Value不能强制转换为DateTime。如果以编程方式添加行,请尝试将DBNull.Value替换为null(Nothing)


原始答案: 最好在加载任何数据之前,对每个保存日期时间数据的列执行此操作:

myDateTimeColumn.ValueType = GetType(DateTime)
根据,ValueType属性“在根据列的单元格内容对列进行筛选或排序时使用”。因此,我会确保为任何允许排序的列设置它


有了这个属性集,网格可以在一个具有空值的列上排序,并将强制插入/更新的单元格转换为DateTime。

下面是我提出的解决方案。DataGridView会引发SortCompare事件,您可以使用该事件输入自定义排序。我正在处理该事件,并使空值排序高于非空值(您可以轻松地使空值低于非空值)。下面是VB代码。我假设每个单元格值都是IComparable(如果不是,它将由正常的错误处理逻辑处理)


如果有人对此有任何改进,请随时发布。

只是为了给这个问题添加一些代码。。。我执行了以下操作,以使DateTime(和其他非字符串类型)的排序在存在空值的情况下正常工作:

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);
}

一个简单的解决方案是添加一个“tonull”函数,每次进行比较时都运行e.cellvalue1和2。如果该值为“”,则如果希望null值在排序中首先出现,则单元格的值将更改为01/01/1001;如果希望null值在排序中最后出现,则单元格的值将更改为01/01/3001或更高的值

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

你说得对,它不是数据绑定的。这是一个很好的建议,但如果可以的话,我更愿意在显示器上保留空值。我会把它作为B计划。我可以试试看。这可能不会比手动处理排序少多少工作,但至少会更有趣。这可能是一种比处理来自某个客户端对象的排序更干净的方法(WinForm类本身就是这种混乱的一个很好的候选者),谢谢您的帖子。我在设计器中定义列,而不是以编程方式,并且我有多个列。我想知道这两种差异是否可以解释不同的结果。请参阅我的最新答案。如果你发布的内容解决了你的问题,那就酷吧。但我想知道我的建议是否也适用于您。如果DataGridView是数据绑定的..SortCompare不起作用。是否有其他替代方法?如果DataGridView是数据绑定的..SortCompare不起作用。还有其他选择吗?
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