Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a DataGridView on multiple columns?

I've searched for an example of sorting a DataGridView on multiple columns, but don't seem to be able to find an example which does what I would like.

Basically, I have a bound DataGridView control (bound to a DataTable/DataView), and the bound DataTable has two columns:- priority and date. I would like to sort by date within priority. That is, the priority column takes precendence, then its the date but both can be ascending or descending.

So, for example, I may have low priority, early date first (order by priority asc, date asc), and, by clicking the date column header, switch to low priority, late date first (order by priority asc, date desc). If I then click on the priority, I would like to have high priority first, then late date (the current sort order for the date column - order by priority desc, date desc), but then be able to click the date column header to switch to high priority, early date (order by priority desc, date asc).

Ideally, I would like sort glyphs on both columns to show ascending or descending.

Any ideas or pointers would be gratefully received.

This (see below) seems to get pretty close, but the glyphs aren't working right.

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
  public partial class Form1 : Form
  {
     DataSet1 dataset;

     public Form1()
     {
        InitializeComponent();

        dataset = new DataSet1(); // two columns: Priority(Int32) and date (DateTime)
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("01-jan-10"));
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("02-jan-10"));
        dataset.DataTable1.AddDataTable1Row(1, DateTime.Parse("03-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("04-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("05-jan-10"));
        dataset.DataTable1.AddDataTable1Row(2, DateTime.Parse("06-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("07-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("08-jan-10"));
        dataset.DataTable1.AddDataTable1Row(3, DateTime.Parse("09-jan-10"));

        dataGridView1.DataSource = dataset.DataTable1.DefaultView;

        dataGridView1.AllowUserToAddRows = false;

        dataGridView1.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
        dataGridView1.Columns[1].SortMode = DataGridViewColumnSortMode.Programmatic;

        dataGridView1.Columns[0].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
        dataGridView1.Columns[1].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
     }

     private void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
     {
        DataGridViewColumn[] column = new[] { dataGridView1.Columns[0], dataGridView1.Columns[1] };

        DataGridViewColumnHeaderCell headerCell = dataGridView1.Columns[e.ColumnIndex].HeaderCell;

        if (headerCell.SortGlyphDirection != SortOrder.Ascending)
           headerCell.SortGlyphDirection = SortOrder.Ascending;
        else
           headerCell.SortGlyphDirection = SortOrder.Descending;

        String sort = column[0].DataPropertyName + " " + fnSortDirection(column[0])
                    + ", "
                    + column[1].DataPropertyName + " " + fnSortDirection(column[1]);
        dataset.DataTable1.DefaultView.Sort = sort;
        this.textBox1.Text = sort;
     }

     private String fnSortDirection(DataGridViewColumn column)
     {
        return column.HeaderCell.SortGlyphDirection != SortOrder.Descending ? "asc" : "desc";
     }
  }
}
like image 642
Black Light Avatar asked Jan 10 '11 12:01

Black Light


People also ask

How to Sort multiple columns in DataGridView in c#?

Sort (this. dataGridView1. Columns["day"], ListSortDirection. Ascending);

How to Sort multiple columns in DataGridView in vb net?

If DataGridView has a DataView as its DataSource, then setting the Sort string for that DataView causes an immediate sort of the DataView, and that sort shows right away in the bound DataGridView control. The Sort string can include multiple columns, each of which can be indicated to sort ASC or DESC.

How to order DataGridView columns in c#?

The DataGridView control in C# provides automatic sorting, so that you can manually sort any column in the datagridview control. You can sort the data in ascending or descending order based on the contents of the specified column. Also you can see the DataGridView sorting when user clicks on the column header.


1 Answers

The first time I read this, I totally missed the part about sorting by multiple columns simultaneously (my fault, not yours; the question was perfectly clear).

If that's the case, you are going to have to write the code that handles this yourself. The provided DataGridView control doesn't support multi-column sorting by default. Fortunately, others have already done a lot of the work to implement this for you. Here are a few samples:

  • DataGridView Multi-column Sort (CodeProject)
  • How To Allow To Sort By Multiple Columns in Custom Data Binding (CodeProject)

Alternatively, if you bind your DataGridView to a data source, that data source can be sorted on multiple columns and the DataGridView control will respect that sorting. Any data source that implements IBindingListView and exposes a Sort property will work for multi-column sorting.


However, regardless of the route that you choose to enable multi-column sorting, you aren't going to have much success in coercing the DataGridView to display the sort arrow glyph on multiple columns. The easiest solution here is to custom draw only the column headers to provide your own sort glyph.

To do this, attach a handler to the DataGridView.CellPainting event and check for a RowIndex of -1 (indicating a column header). There's a full sample of owner-drawn column headers here. I strongly recommend sticking with the conventional arrow icon, but once you go this route, the options are truly unlimited. You can make your column headers look like anything you want, and even indicate the relative weight of each column in the sort order using different icons.

You can also choose to derive a new class from DataGridViewColumnHeaderCell and override its Paint method. This is probably a cleaner, more object-oriented way of accomplishing the same thing.

like image 149
Cody Gray Avatar answered Oct 26 '22 07:10

Cody Gray