DataGridView 对 DateTime 列中的空值进行排序

问题描述 投票:0回答:6

我在 Windows 窗体应用程序中有一个 DataGridView 控件。有四列包含字符串数据,三列包含日期时间数据。我使用 Rows.Add() 方法以编程方式添加行。所有列的 SortMode 设置为“自动”。单击列标题即可进行排序,但包含一些空值的 DateTime 列除外。当用户单击该列的标题时,它会抛出 ArgumentException:对象必须是 DateTime 类型。

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

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

.net winforms datagridview
6个回答
4
投票

一个简单的解决方案是添加一个“tonull”函数,每次进行比较时都运行 e.cellvalue1 和 2。如果值为“”,则如果您希望空值在排序中首先出现,则单元格的值将更改为 01/01/1001;如果您希望它们最后出现,则单元格的值将更改为 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

2
投票

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

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

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


1
投票

如果您动态添加行,我必须假设 DataGridView 不是数据绑定的。 在这种情况下,为什么不在填充相应的行单元格时检查空值并实例化某种虚拟日期(过去的一些有趣的日期,以便清楚地表明它是空值 - 也许还指定它是默认值)这样在排序时就很好了。

如果这不好 - 创建自己的 DataGridView 与内置的完全相同(使用继承)怎么样?但是重写排序方法以忽略空值?


1
投票

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


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

myDateTimeColumn.ValueType = GetType(DateTime)

根据 MSDN,ValueType 属性“在根据单元格内容对列进行过滤或排序时使用”。 所以我一定要为任何允许排序的列设置它。

设置此属性后,网格可以在具有空值的列上排序,并将强制插入/更新的单元格转换为日期时间。


0
投票

只是为了在这个问题中添加一些代码...我执行了以下操作,以便在存在空值的情况下对 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);
}

0
投票

将此代码添加到 SortCompare 事件中:

  Private Sub GridView1_SortCompare(sender As Object, e As DataGridViewSortCompareEventArgs) Handles DgvDetail.SortCompare
  If e.CellValue1 Is Nothing OrElse e.CellValue1.Equals(DBNull.Value) OrElse e.CellValue1.Equals(string.Empty) Then
      If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) OrElse e.CellValue2.Equals(string.Empty) Then
          e.SortResult = 0
      Else
          e.SortResult = 1
      End If
  Else
      If e.CellValue2 Is Nothing OrElse e.CellValue2.Equals(DBNull.Value) OrElse e.CellValue2.Equals(string.Empty) Then
          e.SortResult = -1
      Else
          e.SortResult = DirectCast(e.CellValue1, IComparable).CompareTo(DirectCast(e.CellValue2, IComparable))
      End If
  End If
  e.Handled = True

结束子

© www.soinside.com 2019 - 2024. All rights reserved.