Yellow
Yellow

Reputation: 3966

Sorting numerically in a DataGridViewTextBoxColumn

This question is closely related to these two (this and this) but I don't think they give a satisfying answer.

I have a DataGridView (i.e. a table) with several columns (DataGridViewTextBoxColumn) of different data types: string, integers and floats. When I click on their respective header, each should be sorted according to their type: string alphabetically and numerical values numerically. I have, simply put, the following code:

private System.Windows.Forms.DataGridView grid;
private System.Windows.Forms.DataGridViewTextBoxColumn stringColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn doubleColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn intColumn;


stringColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
doubleColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
intColumn    = new System.Windows.Forms.DataGridViewTextBoxColumn();

grid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        stringColumn,
        doubleColumn,
        intColumn});

However, since the default representation is string, the numerical values also get sorted alphabetically, for example like this:

1, 11, 2, 3, 42, 5

Apparently, as an easy way of getting around this, according some threads (e.g. here and here), the following should work immediately solve the problem:

doubleColumn.ValueType = typeof(double);
intColumn.ValueType = typeof(int);

However, this solution simply doesn't work in my project: values are still sorted alphabetically. So the question is: why not? In the Debugger, I could see that the value type actually changed to (in the double case) System.Double, so something is happening at least. But how can I make sure that it actually sorts it accordingly, without writing my own sorter?

Upvotes: 13

Views: 25697

Answers (6)

danicode
danicode

Reputation: 887

I used this code to order numerically where the column contains a number and to work even when there are alfabetic values.

Private Sub grid_SortCompare(ByVal sender As Object, ByVal e As DataGridViewSortCompareEventArgs) Handles grid.SortCompare
            If e.Column.Index = grid.Columns("colNrFct").Index Then
                If Not isNumeric(e.CellValue1) And Not isNumeric(e.CellValue2) Then
                    e.SortResult = 0
                ElseIf Not isNumeric(e.CellValue1) And isNumeric(e.CellValue2) Then
                    e.SortResult = -1
                ElseIf isNumeric(e.CellValue1) And Not isNumeric(e.CellValue2) Then
                    e.SortResult = 1
                ElseIf Double.Parse(e.CellValue1.ToString()) > Double.Parse(e.CellValue2.ToString()) Then
                    e.SortResult = 1
                ElseIf Double.Parse(e.CellValue1.ToString()) < Double.Parse(e.CellValue2.ToString()) Then
                    e.SortResult = -1
                Else
                    e.SortResult = 0
                End If
    
                e.Handled = True
            End If
        End Sub

Upvotes: 0

joseph alivio
joseph alivio

Reputation: 1

https://www.youtube.com/watch?v=kKeTRPSLxX8 watch this video, it helps a lot

Copying the code from that video:

Private Sub dgvDailySales_SortCompare(sender As Object, e As DataGridViewSortCompareEventArgs) Handles dgvDailySales.SortCompare

Try
            Dim dval1, dval2 As Double

            If Not Double.TryParse(e.CellValue1.ToString, dval1) Then Return
            If Not Double.TryParse(e.CellValue2.ToString, dval2) Then Return

            If dval1 = dval2 Then
                e.SortResult = 0
            ElseIf dval2 > dval1 Then
                e.SortResult = -1
            ElseIf dval1 > dval2 Then
                e.SortResult = 1
            End If
            e.Handled = True
        Catch ex As Exception
            MsgBox(ex.Message, vbCritical)
        End Try
    End Sub

Upvotes: 0

chadianscot
chadianscot

Reputation: 145

Setting your column ValueType to typeof(int) will work, just remember to make sure you put integers into that column. If the rest of your data contains strings, it can be easy to forget to convert your number from a string to an int.

Upvotes: 0

AlexDev
AlexDev

Reputation: 4727

If you are using a DataTable then you have to set the DataType on the DataColumn. Setting ValueType on the DataGridViewTextBoxColumn won't help.

You can set it when creating it:

table.Columns.Add("Number", typeof(int));

Upvotes: 5

explorercris
explorercris

Reputation: 31

Changing column from string to int32 might be helpful:

for (int i = 0; i < tableDataGridView.Rows.Count; i++) {
    DateTime dt = Convert.ToDateTime(tableDataGridView.Rows[i].Cells[9].Value.ToString());
    DateTime dtnow = DateTime.Now;
    TimeSpan ts = dtnow.Subtract(dt);
    tableDataGridView.Rows[i].Cells[1].Value = Convert.ToInt32( ts.Days.ToString());
}
tableDataGridView.Sort(tableDataGridView.Columns[1], ListSortDirection.Descending);

For me, it works. I hope it will help.

Upvotes: 1

King King
King King

Reputation: 63377

You can handle the event SortCompare to change how the sorting is done, like this:

private void dataGridView1_SortCompare(object sender, DataGridViewSortCompareEventArgs e) {
    //Suppose your interested column has index 1
    if (e.Column.Index == 1){
       e.SortResult = int.Parse(e.CellValue1.ToString()).CompareTo(int.Parse(e.CellValue2.ToString()));
       e.Handled = true;//pass by the default sorting
     }
}

NOTE: The above code supposes your cell values are convertible to int.

You said your DataGridView doesn't have DataSource assigned, that means you Add the rows manually, so I think you should use numeric values instead of string for your cells. That would make the sorting work as you want.

Upvotes: 26

Related Questions