在DataGridView中对TimeDifference进行排序的最佳方法

时间:2016-05-11 11:39:13

标签: .net vb.net sorting datetime datagridview

我有以下问题;

我的ListBased application正在阅读我的dabatase中的大量内容。其中一个读取列称为“创建日期”,表示创建订阅的日期时间。我的基于列表的应用程序还计算从创建到现在的TimeDifference以向用户显示此条目已存在多长时间。这些信息以DataGridView显示给用户。

现在使用以下代码:

Dim a As DateTime = row.Item("CreateDate")
Dim min As Integer = DateDiff(DateInterval.Minute, a, Now) Mod 60
Dim h As Integer = DateDiff(DateInterval.Hour, a, Now) Mod 24
Dim d As Integer = DateDiff(DateInterval.Day, a, Now)
dgvRow.Cells(2).Value = d.ToString("00") & ":" & h.ToString("00") & ":" & min.ToString("00")

此代码为我们提供以下时差格式:DD:HH:MM。

问题:如果用户使用DataGridViews的“{1}}”等待时间 - 请将其Sort function当然不正确。

一种可能的解决方案是,例如仅将TimeDif显示为分钟,但是它变得越来越差,对用户来说变得越来越差。

另一种可能的解决方案:只需使用DateTime本身 - 这当然可行,但用户不想自己计算TimeDif。

如何使等待时间列可以排序?

示例:

enter image description here

3 个答案:

答案 0 :(得分:2)

任何数据进行排序或处理的“最佳方式”是其本机形式,而不是它的字符串表示形式,它需要将它们拆开并将它们转换或解析为将要排序的内容正常。

在一段时间内,TimeSpan甚至整数都可以使用。 DGV能够正确排序。

OP没有说,但我认为DGV绑定到表而不是将数据从DB复制到DGV;如果不是这样的话:使用数据总是比用户显示更好。有几种方法可以做到这一点。第一个解决方案将使用TimeSpan列,因为它就是这样,第二个将使用整数列。

时间跨度

填写DataTable后,在其中添加TimeSpan列并填写该列:

Dim dc = New DataColumn("Elapsed", GetType(TimeSpan))
dtSample.Columns.Add(dc)

Dim dtN = DateTime.Now
For Each r As DataRow In dtSample.Rows
    r("Elapsed") = dtN.Subtract(r.Field(Of DateTime)("StartDate"))
Next

总的来说,这就是它的全部。 DGV将知道如何正确排序色谱柱。其余的纯粹是为了处理显示格式(默认情况下,6.01:32:26.7898087 明显不友好)。不幸的是,使用CellStyle格式化不适用于TimeSpan,因此您需要使用CellFormatting(或使用 CustomFormatter技术知道)。

Private Sub dgv2_CellFormatting(sender As Object,... etc
    If e.ColumnIndex = 3 Then
        Dim ts As TimeSpan?      ' Nullable so we can detect fails
        If TypeOf (e.Value) Is TimeSpan Then
            ts = CType(e.Value, TimeSpan)
        End If

        If ts IsNot Nothing Then
            e.Value = String.Format("{0}:{1:00}:{2:00}", ts.Value.Days,
                           ts.Value.Hours, ts.Value.Minutes)
        Else
            e.Value = ""
        End If
        e.FormattingApplied = True
    End If
End Sub

结果:

enter image description here

图像显示排序前后。请注意,单个数字天数自动排序低于10

整数

这可能更简单:不是向DataTable添加列,而是让SQL计算某些基本单位的差异,例如秒:

Dim SQL = "SELECT Id..., DateDiff('s',[StartDate], Now()) AS Elapsed FROM..." 

SQL语法可能会因您的提供商而异,但结果是,查询将计算差异将结果“Elapsed”列添加到生成的DataTable。这个elides循环手动添加值。当然,DGV知道如何对整数进行排序。接下来更改CellFormatting事件以转换为TimeSpan进行显示:

    If e.ColumnIndex = 3 Then
        Dim ts As TimeSpan?      ' Nullable so we can detect fails
        If TypeOf (e.Value) Is Int32 Then
            ts = TimeSpan.FromSeconds(CType(e.Value, Int32))
        End If

        If ts IsNot Nothing Then
            e.Value = String.Format("{0}:{1:00}:{2:00}", ts.Value.Days, ts.Value.Hours, ts.Value.Minutes)
        Else
            e.Value = ""
        End If
        e.FormattingApplied = True
    End If

在这两种情况下,您只是更改数据向用户显示的方式。因此 - 并且因为“Elapsed”是计算值 - 该列不能由用户编辑。使用AutoGenerateColumns = True,您的DGV应该将该列设为ReadOnly。

答案 1 :(得分:0)

您可以通过从Now中减去日期然后使用String.Format来简化代码,以获得所需的代码:

Dim a As DateTime = row.Item("CreateDate")
Dim waitTime = DateTime.Now - a
dgvRow.Cells(2).Value = String.Format("{0:000}:{1:00}:{2:00}", waitTime.TotalDays, waitTime.Hours, waitTime.Minutes)

只要您使用固定长度的日期(长度相同或大于数据中的最长数字)和两位数的小时分钟,当它们按字符串排序时,它们应该在按时间顺序排列

答案 2 :(得分:0)

我自己使用以下代码作为Eventhandler:

Private Sub DataGridView1_SortCompare( _
    ByVal sender As Object, ByVal e As DataGridViewSortCompareEventArgs)
    If DirectCast(sender, DataGridView).SortedColumn.Equals(DirectCast(sender, DataGridView).Columns(2)) Then
        e.SortResult = CInt(e.CellValue1.ToString.Replace(":", "")) - CInt(e.CellValue2.ToString.Replace(":", ""))
        e.Handled = True
    End If
End Sub

由于我刚刚开始工作,它可能仍然包含错误,所以在使用之前要注意这一点。