如何在DataGridView中使用指定的DataSource启用排序?

时间:2013-10-01 09:26:54

标签: c# winforms datagridview gridview-sorting

在几项建议中,我开始为DataSource分配DataGridView而不是DataGridView.Rows.Add(...)。这很方便,因为我的数据源已经是一个不会改变的大列表(很多)。但是,当我使用DataSource赋值时,无法对列进行排序。

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

我还尝试将List<Person>替换为BindingList<Person>BindingSource,但这似乎都不重要。我还尝试添加自定义排序器:

this.SortCompare += MyGridView_SortCompare;

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

但事情甚至没有被召唤。是否有其他方法可以使用DataSource进行排序?

注意:请注意,我的DataSource不一定是SQL,而只是List

2 个答案:

答案 0 :(得分:7)

您需要将数据源强制转换为支持排序的列表(IBindingList和IBindingListView),然后它将开箱即用。网上有很多例子,这是我过去使用的例子:

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

答案 1 :(得分:1)

另一种方法是将List转换为DataTable,然后通过BindingSource将该DataTable绑定到DataGridView。这样,DataGridView将继承DataTable可用的排序选项。

要将列表转换为DataTable,请参阅以下文章: How to fill a datatable with List<T>

相关问题