我有以下问题;
我的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。
如何使等待时间列可以排序?
示例:
答案 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
结果:
图像显示排序前后。请注意,单个数字天数自动排序低于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
由于我刚刚开始工作,它可能仍然包含错误,所以在使用之前要注意这一点。