我在 Windows 窗体应用程序中有一个 DataGridView 控件。有四列包含字符串数据,三列包含日期时间数据。我使用 Rows.Add() 方法以编程方式添加行。所有列的 SortMode 设置为“自动”。单击列标题即可进行排序,但包含一些空值的 DateTime 列除外。当用户单击该列的标题时,它会抛出 ArgumentException:对象必须是 DateTime 类型。
我知道解决这个问题的困难方法:将所有 SortModes 设置为 NotSortable,处理 ColumnHeaderMouseClick 事件并手动对整个事件进行排序。我正在寻找简单的方法。
是否有一个属性或我可以设置的东西,或者其他一些相对简单的方法来允许此列对其中的空值进行排序?
一个简单的解决方案是添加一个“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
这是我想出的解决方案。 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 不是数据绑定的。 在这种情况下,为什么不在填充相应的行单元格时检查空值并实例化某种虚拟日期(过去的一些有趣的日期,以便清楚地表明它是空值 - 也许还指定它是默认值)这样在排序时就很好了。
如果这不好 - 创建自己的 DataGridView 与内置的完全相同(使用继承)怎么样?但是重写排序方法以忽略空值?
更新答案: 查看您发布的答案后,我发现您正在检查单元格中的 DBNull.Value 。 这可能是问题的根源,因为 DBNull.Value 无法转换为 DateTime。 如果您以编程方式添加行,请尝试将 DBNull.Value 替换为 null(无)。
原答案: 尝试对保存日期时间数据的每一列执行此操作,最好在加载任何数据之前:
myDateTimeColumn.ValueType = GetType(DateTime)
根据 MSDN,ValueType 属性“在根据单元格内容对列进行过滤或排序时使用”。 所以我一定要为任何允许排序的列设置它。
设置此属性后,网格可以在具有空值的列上排序,并将强制插入/更新的单元格转换为日期时间。
只是为了在这个问题中添加一些代码...我执行了以下操作,以便在存在空值的情况下对 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);
}
将此代码添加到 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
结束子