【问题标题】:DataGridView sorting with nulls in DateTime columnDataGridView 在 DateTime 列中使用空值进行排序
【发布时间】:2010-10-26 15:00:43
【问题描述】:

我在 Windows 窗体应用程序中有一个 DataGridView 控件。有四列是字符串数据,三列是日期时间数据。我正在使用 Rows.Add() 方法以编程方式添加行。所有列的 SortMode 都设置为 Automatic。单击列标题进行排序只是工作,除了一个具有一些空值的 DateTime 列。当用户单击该列的标题时,它会引发 ArgumentException: Object must be of type DateTime。

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

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

【问题讨论】:

  • 如果 DataGridView 是 DataBound..SortCompare 不起作用。有没有其他选择?

标签: .net winforms datagridview


【解决方案1】:

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

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

【讨论】:

  • 你是对的,它不是 DataBound。这是一个很好的建议,但如果可以的话,我更愿意在显示中保留空值。我会保留它作为 B 计划。
  • 我可以试一试。它的工作量可能不比手动处理排序少,但至少会更有趣。
  • 这可能是一种比处理来自某些客户端对象的排序更干净的方法(WinForm 类本身就是这种修饰的一个很好的候选者)
【解决方案2】:

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


原答案: 尝试对包含 DateTime 数据的每一列执行此操作,最好在加载任何数据之前:

myDateTimeColumn.ValueType = GetType(DateTime)

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

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

【讨论】:

  • 感谢您的帖子。我在设计器中而不是以编程方式定义列,并且我有多个列。我想知道这两个差异是否可以解释不同的结果。
【解决方案3】:

这是我想出的解决方案。 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

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

【讨论】:

  • 查看我的更新答案。如果您发布的内容解决了您的问题,那就太好了。但我很想知道我的建议是否也适合你。
  • 如果 DataGridView 是 DataBound..SortCompare 不起作用。有没有其他选择?
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    一个简单的解决方案是添加一个“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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-22
      • 1970-01-01
      • 2015-10-26
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多