[C#.NET] Implemented Sortable BindingList

  • 8165
  • 0
  • C#
  • 2020-10-07

[C#.NET] Implemented Sortable BindingList

FCL 的 BindingList <T> 沒有提供排序的功能,當 DataGridView 繫結 BindingList<T> 時會無法實現排序功能,上一篇 [C#.NET][Winform] 利用集合排序,重現 DataGridView 資料繫結後的排序 用了很多的方法解掉,而本篇將實現具有排序功能的 BindingList<T> ,用來解決問題

 

章節內容如下

PropertyComparer<T> 類別實作了 IComparer<T> 介面

SortableBindingList<T> 類別實作了 BindingList<T> 類別

用戶端調用

執行結果

範例下載


PropertyComparer<T> 類別實作了 IComparer<T> 介面

使用 PropertyDescriptor 則取出類別屬性資訊

程式碼如下:

public class PropertyComparer<T> : IComparer<T>
{
    private IComparer _comparer;
    private PropertyDescriptor _property;
    private ListSortDirection _sortDirection;

    public PropertyComparer(PropertyDescriptor property, ListSortDirection sortDirection)
    {
        this._property = property;
        this._sortDirection = sortDirection;

        //Type comparerPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);

        //this._comparer = (IComparer)comparerPropertyType.InvokeMember("Default",
        //                                            BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public,
        //                                            null,
        //                                            null,
        //                                            null);
        this._comparer = Comparer.Default;
    }

    public int Compare(T x, T y)
    {
        var reverse = this._sortDirection == ListSortDirection.Ascending ? 1 : -1;
        return reverse * this._comparer.Compare(this._property.GetValue(x), this._property.GetValue(y));
    }

    public void SetDirection(ListSortDirection sortDirection)
    {
        this._sortDirection = sortDirection;
    }
}

 

SortableBindingList<T> 類別實作了 BindingList<T> 類別

  • 原本的 BindingList<T> 不提供Sort 的方法,所以要覆寫有關 Sort 關鍵字的方法,重新給予功能

image

  • 用 Dictionary<string, PropertyComparer<T>> 裝載屬性比較器

程式碼如下:

public class SortableBindingList<T> : BindingList<T>
{
    private readonly Dictionary<string, PropertyComparer<T>> _comparerList = new Dictionary<string, PropertyComparer<T>>();

    private ListSortDirection _sortDirection;
    private PropertyDescriptor _property;

    public SortableBindingList()
        : base(new List<T>())
    {
    }

    public SortableBindingList(IList<T> List)
        : base(List)
    {
    }

    public SortableBindingList(IEnumerable<T> Enumerable)
        : base(new List<T>(Enumerable))
    {
    }

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

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

    protected override PropertyDescriptor SortPropertyCore
    {
        get { return this._property; }
    }

    protected override ListSortDirection SortDirectionCore
    {
        get { return this._sortDirection; }
    }

    //protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection sortDirection)
    //{
    //    List<T> list = (List<T>)this.Items;
    //    var name = property.Name;
    //    PropertyComparer<T> comparer;

    //    if (!this._comparerList.TryGetValue(name, out comparer))
    //    {
    //        comparer = new PropertyComparer<T>(property, sortDirection);
    //        this._comparerList.Add(name, comparer);
    //    }

    //    comparer.SetDirection(sortDirection);
    //    list.Sort(comparer);

    //    this._property = property;
    //    this._sortDirection = sortDirection;
    //    this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
    //}

    protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
    {
        List<T> itemsList = (List<T>)this.Items;
        if (property.PropertyType.GetInterface("IComparable") != null)
        {
            itemsList.Sort((x, y) =>
            {
                if (property.GetValue(x) != null)
                    return ((IComparable)property.GetValue(x)).CompareTo(property.GetValue(y)) *
                           (direction == ListSortDirection.Descending ? -1 : 1);
                else if (property.GetValue(y) != null)
                    return ((IComparable)property.GetValue(y)).CompareTo(property.GetValue(x)) *
                           (direction == ListSortDirection.Descending ? 1 : -1);
                else
                    return 0;
            });
        }
        this._property = property;
        this._sortDirection = direction;
    }
}

 

用戶端調用

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private TimersTimer _timer = null;
    private Random _random = new Random();
    private SortableBindingList<Fields> _fieldList = null;
    private BindingSource _source = new BindingSource();

    private void Form1_Load(object sender, EventArgs e)
    {
        this._fieldList = new SortableBindingList<Fields>(CreateList());
        this._source.DataSource = this._fieldList;
        this.dataGridView1.DataSource = this._source;

        //this._timer = new TimersTimer();
        //this._timer.Interval = 1000;

        //this._timer.Elapsed += _timer_Elapsed;
        //this._timer.Start();
    }

    private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        foreach (var f in this._fieldList)
        {
            f.Number = this._random.Next(1, 1000);
            f.Name = "Name:" + this._random.Next(1, 1000);
            f.Phone = "Phone:" + this._random.Next(1, 1000);
            f.Address = "Address:" + this._random.Next(1, 1000);
        }
    }

    private List<Fields> CreateList()
    {
        List<Fields> fieldList = new List<Fields>();

        for (int i = 0; i < 20; i++)
        {
            Fields f = new Fields();
            f.ID = i + 1;
            f.Number = this._random.Next(1, 1000);
            f.Name = "Name:" + this._random.Next(1, 1000);
            f.Phone = "Phone:" + this._random.Next(1, 1000);
            f.Address = "Address:" + this._random.Next(1, 1000);
            fieldList.Add(f);
        }
        return fieldList;
    }
}

 

執行結果

使用 BindingList<T> 無法排序,沒有箭頭

SNAGHTMLc872ee1

 

使用 SortableBindingList<T> 則可以排序,箭頭出現囉~

SNAGHTMLc884801

 

範例下載

https://github.com/yaochangyu/sample.dotblog/tree/master/Sort/Lab.SortableBindingList


文章出自:http://www.dotblogs.com.tw/yc421206/2013/09/03/116162

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo