排序包含字母和数字的数据视图列

4

我的 DataGridViewDataSource 绑定到了一个 DataView。这个 DataView 等同于我的 dtBills DataTable。代码如下:

Dim View As New DataView
View.Table = DataSet1.Tables("dtBills")
dgvBills.DataSource = View

这个DataGridView有多列,其中一个列包含文本和数字信息。当我点击DataGridView列标题以排序该列时,它像左侧的列一样按字符串排序:

'Curr Col  >>>   ' Wanted Result
10001      >>>   10001
100012     >>>   11000
11000      >>>   12000
110049     >>>   100012
12000      >>>   110049
E-1234     >>>   E-1234
T-12345    >>>   T-1235
T-1235     >>>   T-12345

当我按照平常的方式点击列头时,我该如何对绑定的DataGridView列进行排序?我应该使用DataView来帮助我吗?

2个回答

1
当DataGridView被数据绑定时,无法使用其排序功能,因此需要对源数据进行排序。排序有点复杂,因此我需要两个辅助列。
dgvBills.AutoGenerateColumns = False
tbl.Columns.Add(New DataColumn("Scol1", GetType(String)))
tbl.Columns.Add(New DataColumn("Scol2", GetType(Integer)))

第一个将包含前导字母(或空字符串)。第二个将仅包含字符串中包含的数字。我们将按Scol1,Scol2排序。
现在,我们将所有列设置为Programatic模式(DataGridViewColumnSortMode Enumeration)。
For Each column As DataGridViewColumn In dgvBills.Columns
    column.SortMode = DataGridViewColumnSortMode.Programmatic
Next

自定义排序是在 ColumnHeaderMouseClick 处理程序中实现的 (DataGridView.Sort Method (IComparer))。我们将使用底层视图的排序而不是 Grid 排序。

Private Sub dgvBills_ColumnHeaderMouseClick(sender As Object, e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles dgvBills.ColumnHeaderMouseClick
    Dim newColumn As DataGridViewColumn = dgvBills.Columns(e.ColumnIndex)

    Dim direction As ListSortDirection
    Dim Modifier As String = ""

    If newColumn.HeaderCell.SortGlyphDirection = SortOrder.Ascending Then
        direction = ListSortDirection.Descending
        Modifier = " desc"
    Else
        direction = ListSortDirection.Ascending
    End If

    Dim View As DataView = dgvBills.DataSource

    If {"JobNumber", "JobNumber1"}.Contains(dgvBills.Columns(e.ColumnIndex).Name) Then
        View.Table.Columns("Scol2").Expression = String.Format("Convert(iif (substring({0},1,2) like '*-',substring({0},3,len({0})-1),{0}), 'System.Int32')", dgvBills.Columns(e.ColumnIndex).Name)
        View.Table.Columns("Scol1").Expression = String.Format("iif (substring({0},1,2) like '*-',substring({0},1,2),'')", dgvBills.Columns(e.ColumnIndex).Name)
        View.Sort = String.Format("Scol1 {0},Scol2 {0}", Modifier)
    Else
        dgvBills.Sort(newColumn, direction)
    End If

    If direction = ListSortDirection.Ascending Then
        newColumn.HeaderCell.SortGlyphDirection = SortOrder.Ascending
    Else
        newColumn.HeaderCell.SortGlyphDirection = SortOrder.Descending
    End If

End Sub

{"JobNumber", "JobNumber1"}.Contains ...中,可以设置以不同方式排序的列。其他列按照网格默认排序,或者可以创建另一种自定义排序。
注意:我有一个完全工作的示例,但我希望片段足够好。

这里有几个问题...您手动添加了Scol1和Scol2...我是否应该在我的DataTable中创建另一列名为JobNumber1?此外,当您在表达式中执行substring({0}, 1, 2)时,那应该返回什么?谢谢! - Alex
在我们使用String.Format("Convert( ...)"Scol2的第一个表达式上,我收到了以下错误:输入字符串的格式不正确。 - Alex
以下代码导致错误:View.Table.Columns("Scol2").Expression = String.Format("Convert(Iif(substring({0},1,2) like '*-',substring({0},3,len({0})-1),{0}), 'System.Int32')", DataGridView1.Columns(e.ColumnIndex).Name) - Alex
使用您的原始数据与当前代码,它完美地工作。然而,当我使用来自数据库的DataTable值时,就会出现问题... - Alex
让我们在聊天室里继续这个讨论 - Alex
显示剩余3条评论

1
该列已按字符串正确排序,我想你希望将其按数字排序。问题在于,似乎你所拥有的字符串将数字和字符组合在一起。结果是需要对 DataView 进行相当复杂的排序。
Dim tbl As New DataTable("dtBills")
Dim DataSet1 As New DataSet
DataSet1.Tables.Add(tbl)
tbl.Columns.Add(New DataColumn("MyCol", GetType(String)))
Dim vals As String() = {"10001", "100012", "11000", "110049", "12000", "E-1234", "T-12345", "T-1235"}
For qq = 0 To vals.Length - 1
    Dim row As DataRow
    row = tbl.NewRow
    row(0) = vals(qq)
    tbl.Rows.Add(vals(qq))
Next
tbl = DataSet1.Tables("dtBills")
tbl.Columns.Add(New DataColumn("Scol2", GetType(Integer)) With {.Expression = "Convert(iif (substring(MyCol,1,2) like '*-',substring(MyCol,3,len(MyCol)-1),MyCol), 'System.Int32')"})
tbl.Columns.Add(New DataColumn("Scol1", GetType(String)) With {.Expression = "iif (substring(MyCol,1,2) like '*-',substring(MyCol,1,2),'')"})
Dim View As New DataView(tbl)
View.Sort = "Scol1,Scol2"
View.Table = DataSet1.Tables("dtBills")

所以增加了两列。第一列按照首字母排序,第二列用于按字符串中包含的数字进行排序。

我明白了。如果我只在一列上按字母数字顺序排序,那么这个方法可以奏效...是否有另一种方法可以对每一列(19列)进行这样的排序?如果我按照这种方式做,我将不得不创建许多列,这是否会影响性能?例如,加载时间更长,在我的数据视图上进行行过滤也更长? - Alex
另外,我无法让你的代码正常工作... 你使用子字符串方法的方式有些奇怪 :p - Alex
我猜你想要排序的列名为MyCol。需要将其更改为你的名称。我尝试想出更灵活的方法。我是否正确理解了排序?按数字(如果有),按第一个字母和字母后面的数字排序。 - IvanH
@Alex - Substring函数可以使用2个或3个参数。当使用2个参数时,返回的子字符串从提供的起始值开始,并一直返回到字符串的末尾。如果提供了3个参数,则第三个参数是要返回的字符数。 - Chris Dunaway
@IvanH 我刚刚测试了你的新解决方案。当我启动程序时它可以工作,但是一旦我点击标题以升序/降序排序,它就会回到正常状态... :s - Alex
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接