早期 .NET 開發常用 DataSet/DataTable 作為數據源,DataGridView 綁定時原生支援點擊列標題排序。但隨著領域模型普及,改用 List<T> 或 BindingList<T> 綁定對象集合後,排序功能卻失效了。本文詳細講解如何透過繼承 BindingList<T> 並實作 IComparer<T>,為 WinForms 數據綁定恢復完整的列排序能力。
// 實體類
public struct UserInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Address { get; set; }
}
// 綁定代碼
var list = new BindingList<UserInfo>();
list.Add(new UserInfo { Id = "1", Name = "張三", ... });
list.Add(new UserInfo { Id = "2", Name = "李四", ... });
dataGridView1.DataSource = list; // 點擊列標題無反應
public class ObjectPropertyComparer<T> : IComparer<T>
{
private readonly PropertyDescriptor _property;
private readonly ListSortDirection _direction;
public ObjectPropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
_property = property;
_direction = direction;
}
public int Compare(T x, T y)
{
object xVal = _property.GetValue(x);
object yVal = _property.GetValue(y);
int result;
if (xVal is IComparable comparable)
{
result = comparable.CompareTo(yVal);
}
else if (xVal != null && yVal != null)
{
result = xVal.ToString().CompareTo(yVal.ToString());
}
else
{
result = 0;
}
return _direction == ListSortDirection.Ascending ? result : -result;
}
}
public class SortableBindingList<T> : BindingList<T>
{
private bool _isSorted;
private PropertyDescriptor _sortProperty;
private ListSortDirection _sortDirection;
protected override bool SupportsSortingCore => true;
protected override bool IsSortedCore => _isSorted;
protected override PropertyDescriptor SortPropertyCore => _sortProperty;
protected override ListSortDirection SortDirectionCore => _sortDirection;
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
var items = Items as List<T>;
if (items != null)
{
var comparer = new ObjectPropertyComparer<T>(prop, direction);
items.Sort(comparer);
_isSorted = true;
_sortProperty = prop;
_sortDirection = direction;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
else
{
_isSorted = false;
}
}
protected override void RemoveSortCore()
{
_isSorted = false;
_sortProperty = null;
_sortDirection = ListSortDirection.Ascending;
OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
var sortableList = new SortableBindingList<UserInfo>();
sortableList.Add(new UserInfo { Id = "1", Name = "張三", ... });
sortableList.Add(new UserInfo { Id = "2", Name = "李四", ... });
dataGridView1.DataSource = sortableList; // 現在點擊列標題即可排序
ApplySortCore 接受 ListSortDescriptionCollection 實現多鍵排序。VirtualMode) 配合自定義排序邏輯。Nullable<T> 的 HasValue 情況。採用此模式,既保持了面向對象設計的純粹性,又獲得了與 DataTable 相媲美的 UI 交互體驗。