代码之家  ›  专栏  ›  技术社区  ›  John M Gant aman_novice

在日期时间列中使用空值进行DataGridView排序

  •  3
  • John M Gant aman_novice  · 技术社区  · 15 年前

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

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

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

    5 回复  |  直到 13 年前
        1
  •  4
  •   Tom Callaghan    13 年前

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

    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
  •  2
  •   John M Gant aman_novice    15 年前

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

    如果有人对此有任何改进,请随时张贴。

        3
  •  1
  •   JohnIdol    15 年前

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

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

        4
  •  1
  •   Kyle Gagnet    15 年前

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


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

    myDateTimeColumn.ValueType = GetType(DateTime)
    

    根据 MSDN ,valueType属性是“在筛选或排序与其单元格内容相关的列时使用的。”因此,我将确保为任何允许排序的列设置它。

    使用此属性集,可以对具有空值的列进行排序,并强制将插入/更新的单元格转换为日期时间。

        5
  •  0
  •   liwp    14 年前

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