0

I have a DataGridView that holds data returned from a stored procedure on a database. The columns are different for each return value, so do not have strongly-typed names. I'm currently struggling to order these, as the numeric columns are being ordered as strings, eg. 1 -> 10 -> 11 -> 15 -> 2 -> 25 -> 3, and not by value. I've confirmed that the ValueType of the column is being set correctly. I have tried this:

var sortedRows = from row in _rowArray
                             orderby columnIndex
                             select row;
                _rowArray = sortedRows.ToArray();

where _rowArray is an array of DataRows, and is the DataSource of the DataGridView, and columnIndex is an integer variable specifying which column in _rowArray the user wants to order by. While debugging, I can see that the sortedRows holds the same sequence as _rowArray in the same order, immediately following the LINQ statement. I have also tried:

_rowArray = _rowArray.OrderBy(r => r[columnIndex]).ToArray();

and have tried creating a DataView (view) and done this:

view.Sort = m_data.Tables[0].Columns[columnIndex].ColumnName + " ASC";        

...but that hasn't worked. Anyone offer any insight?

MrShoes
  • 485
  • 10
  • 28

2 Answers2

1

Have you tried parsing the string to int before ordering them?

_rowArray = _rowArray.OrderBy(r => int.Parse(r[columnIndex])).ToArray();
Samy Arous
  • 6,794
  • 13
  • 20
  • That presents its own problems. Firstly, they could be of any value type, not just ints. Secondly, they could be null. Also, I'd need to cast the r[columnIndex] to a string before parsing to Double, int etc. – MrShoes Oct 19 '12 at 10:07
  • Well, if you don't know the value type, you can't simply expect it to be sorted as integer :). The other alternative would be to do the sorting the old way using a Comparer. – Samy Arous Oct 19 '12 at 10:19
  • I can get the data type using var dataType = dataGridView1.Columns[columnIndex].ValueType; – MrShoes Oct 19 '12 at 10:43
  • What I meant is that not every value type can be mapped to an integer value (unless you hash them of course). You will most likely need a different sort method depending to the ValueType. – Samy Arous Oct 19 '12 at 10:46
  • OK. I've tried the below as a hash and confirmed the data case "double" statement is true, but I'm getting an exception due to the string being in incorrect format (ie null). var dataType = dataGridView1.Columns[columnIndex].ValueType; switch (dataType.Name.ToLower()) { case "double": _rowArray = _rowArray.OrderBy(r => double.Parse(r[columnIndex].ToString())).ToArray(); break; } – MrShoes Oct 19 '12 at 10:59
  • This is most likely due to your Culture Settings. In the parse function, you can specify a IFormatProvider. This should give the exact same format that you are getting from the DB – Samy Arous Oct 19 '12 at 11:57
0

Thanks to help from lcfseth, and also the thread here, I've solved this, although it's pretty ugly.

I used the Parse method from the other thread:

public static T Parse<T>(object value)
{
    try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); }
    catch { return default(T); }
}

then my own method has become:

private void SortRows(int columnIndex, ListSortDirection direction)
        {
            if ((_rowArray == null) || (!_rowArray.Any()))
                return;

            dataGridView1.EndEdit();

            RemoveRowDefinitions();

            if (direction == ListSortDirection.Ascending)
            {
                var dataType = dataGridView1.Columns[columnIndex].ValueType;
                try
                {
                    switch (dataType.Name.ToLower())
                    {
                        case "double":
                            _rowArray = _rowArray.OrderBy(r => Parse<double?>(r[columnIndex].ToString())).ToArray();
                            break;
                        case "int32":
                            _rowArray = _rowArray.OrderBy(r => Parse<int?>(r[columnIndex].ToString())).ToArray();
                            break;
                        case "datetime":
                            _rowArray = _rowArray.OrderBy(r => Parse<DateTime?>(r[columnIndex].ToString())).ToArray();
                            break;
                        default:
                            _rowArray = _rowArray.OrderBy(r => r[columnIndex].ToString()).ToArray();
                            break;
                    }
                }
                catch(Exception ex)
                {
                    throw new Exception("Cannot sort on the data type '" + dataType.Name + "'", ex);
                }              
            }

            if (direction == ListSortDirection.Descending)
            {
                var dataType = dataGridView1.Columns[columnIndex].ValueType;
                try
                {
                    switch (dataType.Name.ToLower())
                    {
                        case "double":
                            _rowArray = _rowArray.OrderByDescending(r => Parse<double?>(r[columnIndex].ToString())).ToArray();
                            break;
                        case "int32":
                            _rowArray = _rowArray.OrderByDescending(r => Parse<int?>(r[columnIndex].ToString())).ToArray();
                            break;
                        case "datetime":
                            _rowArray = _rowArray.OrderByDescending(r => Parse<DateTime?>(r[columnIndex].ToString())).ToArray();
                            break;
                        default:
                            _rowArray = _rowArray.OrderByDescending(r => r[columnIndex].ToString()).ToArray();
                            break;
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("Cannot sort on the data type '" + dataType.Name + "'", ex);
                }                    
            }

            dataGridView1.Refresh();
            ApplyRowDefinitions();
            GC.Collect();
        }
Community
  • 1
  • 1
MrShoes
  • 485
  • 10
  • 28