How do I implement automatic sorting of DataGridView?
Asked Answered
K

4

15

I am programmatically adding columns to a DataGridView and then binding to a list. By default, the SortMode of the columns are Automatic. But when I run my app, clicking on the headers does nothing. The up/down arrows aren't showing up. From reading MSDN, not much is said about automatic sorting. They go into more detail about programmatic sorting. So, I'm assuming the automatic way should be easy. MSDN goes on to say "Unless column headers are used for selection, clicking the column header automatically sorts the DataGridView by this column and displays a glyph indicating the sort order." What exactly does that mean? Could I be setting a grid property that conflicts with the sorting? What am I missing?

AutoGenerateColumns = false;
AllowUserToAddRows = false;
AllowUserToDeleteRows = false;
AllowUserToResizeRows = false;
AllowUserToResizeColumns = false;
ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
ReadOnly = true;
MultiSelect = false;
RowHeadersVisible = false;
SelectionMode = DataGridViewSelectionMode.FullRowSelect;
CellBorderStyle = DataGridViewCellBorderStyle.None;


    DataGridViewTextBoxColumn idColumn = new DataGridViewTextBoxColumn();
    idColumn.HeaderText = "ID";
    idColumn.DataPropertyName = "IDNumber";

    DataGridViewTextBoxColumn nameColumn = new DataGridViewTextBoxColumn();
    nameColumn.HeaderText = "Name";
    nameColumn.DataPropertyName = "Description";

    DataGridViewTextBoxColumn lastModifiedColumn = new DataGridViewTextBoxColumn();
    lastModifiedColumn.HeaderText = "Last Modified";
    lastModifiedColumn.DataPropertyName = "Date";

    Columns.Add(idColumn);
    Columns.Add(nameColumn);
    Columns.Add(lastModifiedColumn);

    List<IMyObject> bindingList = GetMyList();
    DataSource = bindingList;
Kellar answered 22/9, 2010 at 15:25 Comment(4)
the glyph they're talking about are the up/down arrows in the column header. try commenting out all your non-default grid settings to see if they're conflicting with the sorting.Seep
I have this same problem. The documentation makes one think that it should just work automatically.Spiegel
Me too! :) And frankly, IMO a grid that doesn't even have basic IComparable-based sorting out of the box is incomplete.Maisiemaison
An alternative solution is documented here : https://mcmap.net/q/588893/-datagridview-sort-and-e-g-bindinglist-lt-t-gt-in-net.Vicious
F
23

We use BindingListView to bind List<T>s to DataGridViews, and it's worked beautifully for us.

Here is a very simple example of creating a view of a list of objects (in C#):

List<Customer> customers = GetCustomers();
BindingListView<Customer> view = new BindingListView<Customer>(customers);
dataGridView1.DataSource = view;

Check out https://mcmap.net/q/590050/-how-to-sort-winforms-datagridview-bound-to-ef-entitycollection-lt-t-gt for a lot more details about DGV sorting and databinding.

If you don't want to add something that heavy, you can try this implementation of a SortableBindingList<T> (with updates).

Both give you sorting right out of the box, and BindingListView is even faster than DataViews, according to their benchmarks.

Fichu answered 18/11, 2010 at 16:33 Comment(7)
I concur, works like a charm :) Although I use the BindingLists from Linq2SQL mostly.Majordomo
Thanks Chris. I think I understand what is happening now. I didn't get that the DataViewGrid control wants to reorder the stored data. I need a solution where the order changes in the control without changing the underlying data source.Spiegel
@leppie: BindingList<> doesn't fix this for me.Orran
@Dan: Read again. You can't just use BindingList<T>, you need a sortable one like the one in the answer.Majordomo
@leppie: Your comment says you use the BindingLists from Linq2SQL. That implies you use BindingList<T> to do this, which isn't the same as the type in the answer.Orran
@Dan: The lists returned by Linq2SQL is a SortableBindingList<T>. This type however is internal, so it returns as a BindingList<T> type. The instance is still sortable.Majordomo
@leppie: Ah, right. I'm not using Linq2SQL, I was just creating an instance of the BindingList<T> type. That explains it, thank you.Orran
T
2

Best solution I've found:

EDIT: Since posting I found this implementation of SortableBindingList(Of T) to be the best solution, with the exception that I modified line 52 to be IEnumerable rather than ICollection, since the constructor is casting anyway and it works.

Alternatively, the solution below needs no custom class:

The DataGridView may be sorted without implementing a custom class. Note that my code is in VB.NET, but it should translate. The data must first be added to the grid.Rows:

For Each item In dataList
    grid.Rows.Add(item.Id, item.Name, item.DateProperty)
Next

Then implement these event handlers. The second one is to ensure that date sorting works. You only need it if your grid will have a sortable date column:

Private Sub grid_ColumnHeaderMouseClick(ByVal sender As Object, ByVal e As DataGridViewCellMouseEventArgs) Handles grid.ColumnHeaderMouseClick
    Dim col = grid.Columns(e.ColumnIndex)
    Dim dir As System.ComponentModel.ListSortDirection

    Select Case col.HeaderCell.SortGlyphDirection
        Case SortOrder.None, SortOrder.Ascending
            dir = System.ComponentModel.ListSortDirection.Ascending
        Case Else
            dir = System.ComponentModel.ListSortDirection.Descending
    End Select

    grid.Sort(col, dir)
End Sub

Private Sub grid_SortCompare(ByVal sender As Object, ByVal e As DataGridViewSortCompareEventArgs) Handles grid.SortCompare
    'This event occurs only when the DataSource property is not set and the VirtualMode property value is false.

    If e.Column.Name = "DateProperty" Then
        e.SortResult = Date.Compare(CType(e.CellValue1, Date), CType(e.CellValue2, Date))

        e.Handled = True
    End If

End Sub

An important thing to note is that only the properties you add to the row are part of the resulting object, since there is no binding. In order to maintain your entire object, you will need to add columns for every property, setting the columns Visible = False for any that should not be displayed.

Thimbleful answered 11/4, 2016 at 15:59 Comment(0)
S
1

I think I found the answer. My datasource implements IList<T>. Apparently it need to implement IBindingList<T>. Unfortunately, I'm not able to test this.

Spiegel answered 18/11, 2010 at 16:27 Comment(2)
You're correct, it does need to implement BindingList. See my answer for a few open-source implementations.Fichu
I implemented DataGridView sorting by hand with a datasource that doesn't implement IBindingList<T>, but I could never get sorting glyphs to show up after a lot of effort. I am pretty sure the code for the sorting glyphs is either bugged or unnecessarily restrictive. They could not even be turned on and set manually.Atlas
T
0

I have just no words .... there exist solution which override default BindingList<>.... because BindingList hides a protected property which is a flag which indicate if the sorting is supported:

enter image description here

msdn:

The SupportsSortingCore property indicates whether the BindingList supports sorting with the ApplySortCore method.

The BindingList class does not provide a base implementation of sorting, so SupportsSortingCore always returns false by default. For more information about implementing sorting, see the ApplySortCore method.

you can strech and brute force properties of you datagrid view, if you are bound to a BindingList<> you will NEVER manage to sort it !

Tyronetyrosinase answered 28/2, 2024 at 15:4 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.