Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable DataGridView sorting when user clicks on the column header?

People also ask

How do you sort data in GridView by clicking column header?

Start by adding a GridView to your web page. To make the columns sortable, you need to set the GridView's property AllowSorting = “true” and OnSorting = “OnSorting”. SortExpression property will hold the name of the column you want to sort.

How to enable sorting in DataGridView c#?

You can then change the numerical cell values into image display values in a handler for the DataGridView. CellFormatting event. In this case, setting the SortMode property to Automatic will enable your users to sort the column.


Set all the column's (which can be sortable by users) SortMode property to Automatic

dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
                                   .OrderBy(s => s.Apellidos)
                                   .ToList();

    foreach(DataGridViewColumn column in dataGridView1.Columns)
    {
    
        column.SortMode = DataGridViewColumnSortMode.Automatic;
    }

Edit: As your datagridview is bound with a linq query, it will not be sorted. So please go through this [404 dead link, see next section] which explains how to create a sortable binding list and to then feed it as datasource to datagridview.

Code as recovered from dead link

Link from above is 404-dead. I recovered the code from the Internet Wayback Machine archive of the page.

public Form1()
{
    InitializeComponent();

    SortableBindingList<person> persons = new SortableBindingList<person>();
    persons.Add(new Person(1, "timvw", new DateTime(1980, 04, 30)));
    persons.Add(new Person(2, "John Doe", DateTime.Now));

    this.dataGridView1.AutoGenerateColumns = false;
    this.ColumnId.DataPropertyName = "Id";
    this.ColumnName.DataPropertyName = "Name";
    this.ColumnBirthday.DataPropertyName = "Birthday";
    this.dataGridView1.DataSource = persons;
}

As Niraj suggested, use a SortableBindingList. I've used this very successfully with the DataGridView.

Here's a link to the updated code I used - Presenting the SortableBindingList - Take Two - archive

Just add the two source files to your project, and you'll be in business.

Source is in SortableBindingList.zip - 404 dead link


One more way to do this is using "System.Linq.Dynamic" library. You can get this library from Nuget. No need of any custom implementations or sortable List :)

using System.Linq.Dynamic;
private bool sortAscending = false;

private void dataGridView_ColumnHeaderMouseClick ( object sender, DataGridViewCellMouseEventArgs e )
{
    if ( sortAscending )
        dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).ToList ( );
    else
        dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).Reverse ( ).ToList ( );
    sortAscending = !sortAscending;
}

You don't need to create a binding datasource. If you want to apply sorting for all of your columns, here is a more generic solution of mine;

private int _previousIndex;
private bool _sortDirection;

private void gridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == _previousIndex)
        _sortDirection ^= true; // toggle direction

    gridView.DataSource = SortData(
        (List<MainGridViewModel>)gridReview.DataSource, gridReview.Columns[e.ColumnIndex].Name, _sortDirection);

    _previousIndex = e.ColumnIndex;
}

public List<MainGridViewModel> SortData(List<MainGridViewModel> list, string column, bool ascending)
{
    return ascending ? 
        list.OrderBy(_ => _.GetType().GetProperty(column).GetValue(_)).ToList() :
        list.OrderByDescending(_ => _.GetType().GetProperty(column).GetValue(_)).ToList();
}

Make sure you subscribe your data grid to the event ColumnHeaderMouseClick. When the user clicks on the column it will sort by descending. If the same column header is clicked again, sorting will be applied by ascending.


You can use DataGridViewColoumnHeaderMouseClick event like this :

Private string order = String.Empty;
private void dgvDepartment_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
    if (order == "d")
{
        order = "a";                
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })   .OrderBy(s => s.Apellidos).ToList();
    }
    else
    {
        order = "d";
        dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }.OrderByDescending(s => s.Apellidos)  .ToList()
    }
}

your data grid needs to be bound to a sortable list in the first place.

Create this event handler:

    void MakeColumnsSortable_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
    {
        //Add this as an event on DataBindingComplete
        DataGridView dataGridView = sender as DataGridView;
        if (dataGridView == null)
        {
            var ex = new InvalidOperationException("This event is for a DataGridView type senders only.");
            ex.Data.Add("Sender type", sender.GetType().Name);
            throw ex;
        }

        foreach (DataGridViewColumn column in dataGridView.Columns)
            column.SortMode = DataGridViewColumnSortMode.Automatic;
    }

And initialize the event of each of your datragrids like this:

        dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;