How do you enable Sorting in a DataGridView with an assigned DataSource?

心不动则不痛 提交于 2021-02-06 13:59:42

问题


On several recommendations, I started to assign a DataSource to my DataGridView instead of using DataGridView.Rows.Add(...). This is convenient since my data source is already a big list which doesn't change (much). However, when I use the DataSource assignment, it becomes impossible to sort the columns.

class MyGridView : DataGridView
{
    private List<Person> m_personList;

    private class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Person(string first, string last)
        {
            FirstName = first;
            LastName = last;
        }
    }

    public MyGridView()
    {
         /* ...initialise stuff... */
         m_personList.Add(new Person("Kate", "Smith"));
         m_personList.Add(new Person("Bill", "Davids"));
         m_personList.Add(new Person("Ann", "Roth"));

         this.DataSource = m_personList; 
    }
}

I also tried to replace List<Person> by BindingList<Person> and by BindingSource, but none of that seems to matter. I also tried adding a custom sorter:

this.SortCompare += MyGridView_SortCompare;

private void MyGridView_SortCompare(object sender, EventArgs e)
{
    /* ...Compare method...*/
}

but the thing doesn't even get called. Is there some other way to enable sorting with a DataSource?

Note: Note that my DataSource is not (necessarily) an SQL one, but just any List.


回答1:


You need to coerce your datasource into a list that supports sorting (IBindingList and IBindingListView), and then it will work out of the box. There are lots of examples on the web, this is the one I've used in the past:

// usage:
// var sortableList = new SortableList(m_personList);
// dgv.DataSource = m_sortableList; 


/// <summary>
///  Suitable for binding to DataGridView when column sorting is required
/// </summary>
/// <typeparam name="T"></typeparam>
public class SortableList<T> : BindingList<T>, IBindingListView
{
    private PropertyComparerCollection<T> sorts;

    public SortableList()
    {
    }

    public SortableList(IEnumerable<T> initialList)
    {
        foreach (T item in initialList)
        {
            this.Add(item);
        }
    }

    public SortableList<T> ApplyFilter(Func<T, bool> func)
    {
        SortableList<T> newList = new SortableList<T>();
        foreach (var item in this.Where(func))
        {
            newList.Add(item);
        }

        return newList;
    }

    protected override bool IsSortedCore
    {
        get { return this.sorts != null; }
    }

    protected override bool SupportsSortingCore
    {
        get { return true; }
    }

    protected override ListSortDirection SortDirectionCore
    {
        get
        {
            return this.sorts == null
                       ? ListSortDirection.Ascending
                       : this.sorts.PrimaryDirection;
        }
    }

    protected override PropertyDescriptor SortPropertyCore
    {
        get
        {
            return this.sorts == null ? null : this.sorts.PrimaryProperty;
        }
    }

    public void ApplySort(ListSortDescriptionCollection
                              sortCollection)
    {
        bool oldRaise = RaiseListChangedEvents;
        RaiseListChangedEvents = false;
        try
        {
            PropertyComparerCollection<T> tmp
                = new PropertyComparerCollection<T>(sortCollection);
            List<T> items = new List<T>(this);
            items.Sort(tmp);
            int index = 0;
            foreach (T item in items)
            {
                SetItem(index++, item);
            }
            this.sorts = tmp;
        }
        finally
        {
            RaiseListChangedEvents = oldRaise;
            ResetBindings();
        }
    }

    public bool Exists(Predicate<T> func)
    {
        return new List<T>(this).Exists(func);
    }

    string IBindingListView.Filter
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }

    void IBindingListView.RemoveFilter()
    {
        throw new NotImplementedException();
    }

    ListSortDescriptionCollection IBindingListView.SortDescriptions
    {
        get { return (this.sorts == null ? null : this.sorts.Sorts); }
    }

    bool IBindingListView.SupportsAdvancedSorting
    {
        get { return true; }
    }

    bool IBindingListView.SupportsFiltering
    {
        get { return false; }
    }

    protected override void RemoveSortCore()
    {
        this.sorts = null;
    }

    protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
    {
        ListSortDescription[] arr = { new ListSortDescription(prop, direction) };
        ApplySort(new ListSortDescriptionCollection(arr));
    }
}

public class PropertyComparerCollection<T> : IComparer<T>
{
    private readonly PropertyComparer<T>[] comparers;

    private readonly ListSortDescriptionCollection sorts;

    public PropertyComparerCollection(ListSortDescriptionCollection
                                          sorts)
    {
        if (sorts == null)
        {
            throw new ArgumentNullException("sorts");
        }
        this.sorts = sorts;
        List<PropertyComparer<T>> list = new
            List<PropertyComparer<T>>();

        foreach (ListSortDescription item in sorts)
        {
            list.Add(new PropertyComparer<T>(item.PropertyDescriptor,
                                             item.SortDirection == ListSortDirection.Descending));
        }

        this.comparers = list.ToArray();
    }

    public ListSortDescriptionCollection Sorts
    {
        get { return this.sorts; }
    }

    public PropertyDescriptor PrimaryProperty
    {
        get
        {
            return this.comparers.Length == 0
                       ? null
                       : this.comparers[0].Property;
        }
    }

    public ListSortDirection PrimaryDirection
    {
        get
        {
            return this.comparers.Length == 0
                       ? ListSortDirection.Ascending
                       : this.comparers[0].Descending
                             ? ListSortDirection.Descending
                             : ListSortDirection.Ascending;
        }
    }

    int IComparer<T>.Compare(T x, T y)
    {
        int result = 0;
        foreach (PropertyComparer<T> t in this.comparers)
        {
            result = t.Compare(x, y);
            if (result != 0)
            {
                break;
            }
        }
        return result;
    }
}

public class PropertyComparer<T> : IComparer<T>
{
    private readonly bool descending;

    private readonly PropertyDescriptor property;

    public PropertyComparer(PropertyDescriptor property, bool descending)
    {
        if (property == null)
        {
            throw new ArgumentNullException("property");
        }

        this.descending = descending;
        this.property = property;
    }

    public bool Descending
    {
        get { return this.descending; }
    }

    public PropertyDescriptor Property
    {
        get { return this.property; }
    }

    public int Compare(T x, T y)
    {
        int value = Comparer.Default.Compare(this.property.GetValue(x),
                                             this.property.GetValue(y));
        return this.descending ? -value : value;
    }
}



回答2:


An alternate is to convert your List into DataTable and then bind that DataTable to the DataGridView through BindingSource. This way your DataGridView will inherit the sort options available with the DataTable.

For converting a list to DataTable, refer the article: How to fill a datatable with List<T>



来源:https://stackoverflow.com/questions/19112568/how-do-you-enable-sorting-in-a-datagridview-with-an-assigned-datasource

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!