Click here to Skip to main content
15,867,835 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am trying to sort a DataGridView. When I click on the header, I keep getting this error:
'DataGridView control must be bound to an IBindingList object to be sorted.'

I have this query:
List<ArtistList> xList = new List<ArtistList>();
xList = (from a in context.Artists
     orderby a.BirthName
     select new ArtistList
     {
          ArtistId = a.ArtistId,
          Last_Name = a.BirthName.Split(space).Last(),
          Age = DateTime.Today.Year - a.DateOfBirth.Year,
          Song_Count = a.Songs.Count
     }).ToList();

dgvArtists.DataSource = xList;

This is the ArtistList class:
class ArtistList
    {
        public int ArtistId { get; set; }
        public string Last_Name { get; set; }
        public int Age { get; set; }
        public int Song_Count  { get; set; }
    }

This is the header method that is being activated where I am getting the error. The error comes from the first case statement.
private void dgvArtists_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (dgvArtists.Columns[e.ColumnIndex].SortMode != DataGridViewColumnSortMode.NotSortable)
            {
                if (e.ColumnIndex == newSortColumn)
                {
                    if (newColumnDirection == ListSortDirection.Ascending)
                        newColumnDirection = ListSortDirection.Descending;
                    else
                        newColumnDirection = ListSortDirection.Ascending;
                }

                newSortColumn = e.ColumnIndex;

                switch (newColumnDirection)
                {
                    case ListSortDirection.Ascending:
                        dgvArtists.Sort(dgvArtists.Columns[newSortColumn], ListSortDirection.Ascending);
                        break;
                    case ListSortDirection.Descending:
                        dgvArtists.Sort(dgvArtists.Columns[newSortColumn], ListSortDirection.Descending);
                        break;
                }
            }
        }


What I have tried:

I have read: Implementing a Sortable BindingList Very, Very Quickly[^]

I've created a class that only contains the properties I want it to return like it says in:
Cannot convert from System.Linq.IQueryable<AnonymousType> to System.Collections.Generic.IEnumerable<myobject>[^]

My original DataSource was but I have since learned the datasource was created dynamically and no longer exists after it has been given to DataGridView:
dgvArtists.DataSource = (from a in context.Artists
                              orderby a.BirthName
                              select new
                              {
                                  a.ArtistId,
                                  a.BirthName,
                                  a.DateOfBirth,
                                  a.Songs.Count
                              }).ToList();

I have been working on this for a couple of weeks and I cannot seem to get it to turn into an IBindingList object. What am I missing?
Posted
Updated 3-Aug-22 9:21am

1 solution

I'd suggest to use that class: SortableBindingList<T> (for Windows.Forms)[^]

Here is a copy of that class:

C#
public class SortableBindingList<T> : BindingList<T> where T : class
{
    private bool _isSorted;
    private ListSortDirection _sortDirection = ListSortDirection.Ascending;
    private PropertyDescriptor _sortProperty;

    /// <summary>
    /// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
    /// </summary>
    public SortableBindingList()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
    /// </summary>
    /// <param name="list">An <see cref="T:System.Collections.Generic.IList`1" /> of items to be contained in the <see cref="T:System.ComponentModel.BindingList`1" />.</param>
    public SortableBindingList(IList<T> list)
        :base(list)
    {
    }

    /// <summary>
    /// Gets a value indicating whether the list supports sorting.
    /// </summary>
    protected override bool SupportsSortingCore
    {
        get { return true; }
    }

    /// <summary>
    /// Gets a value indicating whether the list is sorted.
    /// </summary>
    protected override bool IsSortedCore
    {
        get { return _isSorted; }
    }

    /// <summary>
    /// Gets the direction the list is sorted.
    /// </summary>
    protected override ListSortDirection SortDirectionCore
    {
        get { return _sortDirection; }
    }

    /// <summary>
    /// Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns null
    /// </summary>
    protected override PropertyDescriptor SortPropertyCore
    {
        get { return _sortProperty; }
    }

    /// <summary>
    /// Removes any sort applied with ApplySortCore if sorting is implemented
    /// </summary>
    protected override void RemoveSortCore()
    {
        _sortDirection = ListSortDirection.Ascending;
        _sortProperty = null;
        _isSorted = false; //thanks Luca
    }

    /// <summary>
    /// Sorts the items if overridden in a derived class
    /// </summary>
    /// <param name="prop"></param>
    /// <param name="direction"></param>
    protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
    {
        _sortProperty = prop;
        _sortDirection = direction;

        List<T> list = Items as List<T>;
        if (list == null) return;

        list.Sort(Compare);

        _isSorted = true;
        //fire an event that the list has been changed.
        OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
    }


    private int Compare(T lhs, T rhs)
    {
        var result = OnComparison(lhs, rhs);
        //invert if descending
        if (_sortDirection == ListSortDirection.Descending)
            result = -result;
        return result;
    }

    private int OnComparison(T lhs, T rhs)
    {
        object lhsValue = lhs == null ? null : _sortProperty.GetValue(lhs);
        object rhsValue = rhs == null ? null : _sortProperty.GetValue(rhs);
        if (lhsValue == null)
        {
            return (rhsValue == null) ? 0 : -1; //nulls are equal
        }
        if (rhsValue == null)
        {
            return 1; //first has value, second doesn't
        }
        if (lhsValue is IComparable)
        {
            return ((IComparable)lhsValue).CompareTo(rhsValue);
        }
        if (lhsValue.Equals(rhsValue))
        {
            return 0; //both are the same
        }
        //not comparable, compare ToString
        return lhsValue.ToString().CompareTo(rhsValue.ToString());
    }
}


[EDIT]
According to the discussion under this solution, especially to this:
User-15670402 wrote:

C#
SortableBindingList<ArtistList> xList = new SortableBindingList<ArtistList>();
xList = (from a in context.Artists
     orderby a.BirthName
     select new ArtistList
     {
          ArtistId = a.ArtistId,
          Last_Name = a.BirthName.Split(space).Last(),
          Age = DateTime.Today.Year - a.DateOfBirth.Year,
          Song_Count = a.Songs.Count
     }).ToList();

dgvArtists.DataSource = xList;

Now my query is giving me an error that says: Cannot implicitly convert type 'System.Collections.Generic.List<final.artistlist>' to 'Final.SortableBindingList<final.artistlists>'


Well... You're doing it wrong. Steps to do:
C#
List<ArtistList> xList = context..
    ...
    .ToList();

BindingList<ArtistList> blArtists = new BindingList<ArtistList>(xList);
SortableBindingList<ArtistList> sblArtists = new SortableBindingList<ArtistList>(bl);
dgvArtists.DataSource = blArtists;


Good luck!
 
Share this answer
 
v3
Comments
User-15670402 3-Aug-22 21:16pm    
So I added the SortableBindingList class and then created a list.
SortableBindingList<ArtistList> xList = new SortableBindingList<ArtistList>();

Now my query is giving me an error that says: Cannot implicitly convert type 'System.Collections.Generic.List<final.artistlist>' to 'Final.SortableBindingList<final.artistlists>'
Maciej Los 4-Aug-22 11:09am    
What kind of query?
User-15670402 4-Aug-22 12:28pm    
This one:
SortableBindingList<ArtistList> xList = new SortableBindingList<ArtistList>();
xList = (from a in context.Artists
     orderby a.BirthName
     select new ArtistList
     {
          ArtistId = a.ArtistId,
          Last_Name = a.BirthName.Split(space).Last(),
          Age = DateTime.Today.Year - a.DateOfBirth.Year,
          Song_Count = a.Songs.Count
     }).ToList();

dgvArtists.DataSource = xList;
Maciej Los 4-Aug-22 14:20pm    
See updated answer. :)
Richard MacCutchan 4-Aug-22 3:42am    
+5, something I need to try.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900