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

172,754

Solution 1

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;
}

Solution 2

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

Solution 3

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;
}

Solution 4

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.

Solution 5

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()
    }
}
Share:
172,754

Related videos on Youtube

Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I have a datagridview on my form and I populate it with this:

    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();
    

    Now, I use the s.Apellidos as the default sort, but I'd also like to allow users to sort when clicking on the column header.

    This sort will not modify the data in any way, it's just a client side bonus to allow for easier searching for information when scanning the screen with their eyes.

    Thanks for the suggestions.

  • Admin
    Admin about 13 years
    Since I want all columns to be sortable, is there a way to programatically iterate through each column and set this property?
  • Admin
    Admin about 13 years
    @Niraj: I get a compiler error. I tried changing your answer to column.Name but it doesn't seem to modify the sorting in any way.
  • Admin
    Admin about 13 years
    @Niraj: You edited your answer. Before it was just 'column' and it would fire a compiler error. I changed it to column.Name to make it work then you changed your answer. However this still doesn't allow me to sort the information.
  • Marshal
    Marshal about 13 years
    @Sergio: So if I understand correctly, now you doesn't get any error but still the columns are not sortable.
  • Admin
    Admin about 13 years
    @Niraj: Correct. I click on the column header and the rows don't order themselves.
  • Marshal
    Marshal about 13 years
    @Sergio: Please refer this link and also take look at edit part of the answer
  • Mehran
    Mehran almost 12 years
    This solution does not need LINQ and works in .net 2.0 and there are other useful functionality to be found in BindingList like change notification. Thanks for sharing.
  • Stephen Turner
    Stephen Turner about 11 years
    I liked the idea of using the DataBindingComplete event, but this doesn't address not having a sortable dataset. I've edited it to make it a bit more reusable
  • Tim Schmelter
    Tim Schmelter over 9 years
    Btw, your foreach could be simpler: foreach(DataGridViewColumn column in dataGridView1.Columns) column.SortMode = DataGridViewColumnSortMode.Automatic;
  • Mahdi Rashidi
    Mahdi Rashidi almost 9 years
    i wanna use this idea, but how can i manage which column header clicked? to sort datagridview order by that specific column name? thanks
  • Arend
    Arend over 7 years
    The source does not exist anymore, is there anyway to update this?
  • jjspierx
    jjspierx about 7 years
    @mr.dev.eloper - The DataGridViewCellMouseEventArgs object contains the "ColumnIndex" property.
  • Milad
    Milad about 7 years
    This answer helped me to figure out a solution for my problem. Here is my answer: stackoverflow.com/a/43997006/6186647
  • Scope Creep
    Scope Creep over 6 years
    Works like a charm, can't believe no one had given you positive feedback for this yet
  • timanderson
    timanderson almost 6 years
    Nice solution. Thanks.
  • Hopeless
    Hopeless almost 6 years
    Use OrderByDescending for the else case would be better.
  • hyukkyulee
    hyukkyulee about 4 years
    works great! Dont forget to add dataGridView.ColumnHeaderMouseClick += dataGridView_ColumnHeaderMouseClick; And to implement this for BindingList which updates every time when data come in... you have to modify the code... dataGridView.DataSource = new BindingList<Data>(dataList.OrderBy(dataGridView.Columns[e.Co‌​lumnIndex].DataPrope‌​rtyName).ToList());
  • Matthew M.
    Matthew M. over 3 years
    Exactly what I was looking for. Thanks.
  • Walter Stabosz
    Walter Stabosz over 3 years
    @Arend I added links to the wayback machine archive of the dead link
  • Carsten
    Carsten over 2 years
    Just passing a DataTable did the trick for me. No fiddling with addition modules etc. Thanky you so much!