سؤال

My DataGridView's DataSource is bound to a DataView. The DataView is equal to my dtBills DataTable. Like so:

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

I have multiple columns in this DataGridView. One in particular has strings and integers as information. When I click on the DataGridView Column Header to sort the column, it sorts as strings like the column on the left:

'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

How would I go about sorting a bound DataGridView Column when pressing on the Column Header as I normally would? Should I use my DataView to help me out?

هل كانت مفيدة؟

المحلول

When a DataGridView is databound it is not possible to use its sorting and it is necessary to sort source data. The sorting is a bit complicated so I need two helper columns.

dgvBills.AutoGenerateColumns = False
tbl.Columns.Add(New DataColumn("Scol1", GetType(String)))
tbl.Columns.Add(New DataColumn("Scol2", GetType(Integer)))

The first one will contain a leading letters (or empty string). The second will contain only a number contained in the string. We will sort by Scol1, Scol2.

Now we set all comumns to Programatic mode (DataGridViewColumnSortMode Enumeration)

For Each column As DataGridViewColumn In dgvBills.Columns
    column.SortMode = DataGridViewColumnSortMode.Programmatic
Next

And custom sorting is achieved in a handler of ColumnHeaderMouseClick (DataGridView.Sort Method (IComparer)). We will use sorting of the underlying view instead of the Grid sorting.

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

In {"JobNumber", "JobNumber1"}.Contains ... is possible to set columns which are sorted differntly. Other columns are sorted as the Grid sorts them by default or it is possible to create another custom sorting.

Note: I have fully working example but I hope that fragments are good enough.

نصائح أخرى

The column is sorted correctly as strings and I suppose you want to sort it as numbers. The problem is that it seems that the strings you have combine numbers and characters. The result is necessity rather complex sorting for a 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")

So two new columns are added. The first maintain sorting by initial letters the second to enable sorting by the number contained in the a string.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top