Hello,

I've got a problem. I created a DataGridView, where a DataTable is it's DataSource. There is a column named "Age" i this DataGridView. It's format is string as I accept the value "unknown". The problem occurs when i try to sort it. After descending sorting the rows where "Age" value is "unknown" are placed at the top of the table. I'd like them to stay at the bottom of the table, no matter if the sort mode is descending or ascending. I've tried to modify the sorting function, but it doesn't work. I tried to follow the pattern from msdn and created my own IComparer.

private class RowComparer : System.Collections.IComparer
{
...
}

dataGridView1.Sort(new RowComparer());

and here the debugger showed the following error:
"DataGridView control is data-bound. The control cannot use the comparer to perform the sort operation."


Please help me if you can
Bye

Recommended Answers

All 2 Replies

This wasn't an easy task. I read the thread and thought it would be an easy answer, but it isn't. The most portable solution I found given the ways to do it is to use hidden columns. Here is how I went about doing it:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace daniweb.grid.customsort
{
  public partial class Form1 : Form
  {
    private DataTable dt;
    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      dt = GetTestData();
      CloneAgeColumn(dt);
      dataGridView1.DataSource = dt;
      dataGridView1.Columns["Age"].SortMode = DataGridViewColumnSortMode.Programmatic;
      dataGridView1.Columns["Age_asc"].Visible = false;
      dataGridView1.Columns["Age_desc"].Visible = false;
      dataGridView1.ReadOnly = true;
    }

    private static DataTable GetTestData()
    {
      DataTable dt = new DataTable();
      dt.Columns.Add(new DataColumn("Name", typeof(string)));
      dt.Columns.Add(new DataColumn("Age", typeof(string)));
      {
        DataRow row = dt.NewRow();
        row["Name"] = "scott";
        row["Age"] = "24";
        dt.Rows.Add(row);
      }
      {
        DataRow row = dt.NewRow();
        row["Name"] = "paul";
        row["Age"] = "92";
        dt.Rows.Add(row);
      }
      {
        DataRow row = dt.NewRow();
        row["Name"] = "jake";
        row["Age"] = "unknown";
        dt.Rows.Add(row);
      }
      {
        DataRow row = dt.NewRow();
        row["Name"] = "mary";
        row["Age"] = "26";
        dt.Rows.Add(row);
      }
      {
        DataRow row = dt.NewRow();
        row["Name"] = "grandma";
        row["Age"] = "unknown";
        dt.Rows.Add(row);
      }
      return dt;
    }

    private static void CloneAgeColumn(DataTable dt)
    {
      dt.Columns.Add("Age_asc", typeof(int));
      dt.Columns.Add("Age_desc", typeof(int));
      for (int i1 = 0; i1 < dt.Rows.Count; i1++)
      {
        int age;
        DataRow row = dt.Rows[i1];
        if (int.TryParse(Convert.ToString(row["Age"]), out age))
        {
          row["Age_asc"] = age;
          row["Age_desc"] = age;
        }
        else
        {
          //Failed to parse, "unknown" age
          row["Age_asc"] = int.MaxValue; //max
          row["Age_desc"] = int.MinValue; //min
        }
      }
    }

    private void button2_Click(object sender, EventArgs e)
    {
      System.Diagnostics.Debugger.Break();
    }

    private void dataGridView1_ColumnSortModeChanged(object sender, DataGridViewColumnEventArgs e)
    {
      //System.Diagnostics.Debugger.Break();
    }

    private void dataGridView1_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
    {
      //System.Diagnostics.Debugger.Break();
    }

    private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
    {
      if (string.Compare(dataGridView1.Columns[e.ColumnIndex].DataPropertyName, "Age", true) == 0)
      {
        switch (dataGridView1.Columns["Age"].HeaderCell.SortGlyphDirection)
        {
          case SortOrder.Ascending:
            dataGridView1.Sort(dataGridView1.Columns["Age_desc"], ListSortDirection.Descending);
            dataGridView1.Columns["Age"].HeaderCell.SortGlyphDirection = SortOrder.Descending;
            break;

          case SortOrder.Descending:
          case SortOrder.None:
            dataGridView1.Sort(dataGridView1.Columns["Age_asc"], ListSortDirection.Ascending);
            dataGridView1.Columns["Age"].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
            break;

          default:
            throw new InvalidEnumArgumentException("SortOrder", (int)dataGridView1.Columns["Age"].HeaderCell.SortGlyphDirection, typeof(SortOrder));
        }
        
      }
      else
      {
        dataGridView1.Columns["Age"].HeaderCell.SortGlyphDirection = SortOrder.None;
      }
    }

  }
}

I have attached the project.

That's it! Thank you very much! I thought about something similar (based on only one additional column), but was unable to make it work :)
That's a brilliant reply. Everythig woks, as it should. I'm just wondering why such an important thing hasn't yet been solved by the VS authors.. Strange, isn't it?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.