[C#.NET] Implemented Sortable BindingList
FCL 的 BindingList <T> 沒有提供排序的功能,當 DataGridView 繫結 BindingList<T> 時會無法實現排序功能,上一篇 [C#.NET][Winform] 利用集合排序,重現 DataGridView 資料繫結後的排序 用了很多的方法解掉,而本篇將實現具有排序功能的 BindingList<T> ,用來解決問題
章節內容如下
PropertyComparer<T> 類別實作了 IComparer<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 關鍵字的方法,重新給予功能
- 用 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> 無法排序,沒有箭頭
使用 SortableBindingList<T> 則可以排序,箭頭出現囉~
範例下載
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