DataGridView绑定BindingList后列头点击排序功能失效
问题原因
默认的BindingList<T>并未实现排序功能,DataGridView的Automatic排序模式依赖数据源实现IBindingList接口中的排序相关成员(包括SupportsSorting属性、SortProperty、SortDirection以及ApplySort方法),但原生BindingList<T>仅提供了IBindingList的基础功能,未支持排序逻辑,因此即使设置SortMode = Automatic也不会生效。
解决方案
以下是几种可行的解决方法:
方法1:使用自定义可排序BindingList
创建继承自BindingList<T>的子类,实现排序所需的接口成员:
public class SortableBindingList<T> : BindingList<T> { private bool _isSorted; private ListSortDirection _sortDirection; private PropertyDescriptor _sortProperty; protected override bool SupportsSortingCore => true; protected override bool IsSortedCore => _isSorted; protected override ListSortDirection SortDirectionCore => _sortDirection; protected override PropertyDescriptor SortPropertyCore => _sortProperty; protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { var items = Items as List<T>; if (items == null || prop == null) return; items.Sort((a, b) => { var valueA = prop.GetValue(a); var valueB = prop.GetValue(b); return direction == ListSortDirection.Ascending ? Comparer.Default.Compare(valueA, valueB) : Comparer.Default.Compare(valueB, valueA); }); _sortProperty = prop; _sortDirection = direction; _isSorted = true; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } protected override void RemoveSortCore() { _isSorted = false; _sortProperty = null; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } }
将原代码中的BindingList<SimpleTask>替换为自定义的SortableBindingList<SimpleTask>:
var bindingList = new SortableBindingList<SimpleTask>(); bindingList.Add(new SimpleTask { Title = "Complete project", CategoryName = "Work" }); bindingList.Add(new SimpleTask { Title = "Buy groceries", CategoryName = "Personal" });
替换后,DataGridView的自动排序功能即可正常工作,点击列头会显示排序图标并完成排序。
方法2:改用List作为BindingSource数据源
BindingSource对List<T>提供了内置排序支持,直接使用List<T>绑定即可:
// 替换原BindingList为List<T> var taskList = new List<SimpleTask>(); taskList.Add(new SimpleTask { Title = "Complete project", CategoryName = "Work" }); taskList.Add(new SimpleTask { Title = "Buy groceries", CategoryName = "Personal" }); tasksBinding.DataSource = taskList;
这种方式更简洁,适合不需要BindingList动态更新通知(如添加/删除项自动刷新UI)的场景,若需手动刷新可调用tasksBinding.ResetBindings(false)。
方法3:手动处理列头点击事件
若不想修改数据源,可监听DataGridView的ColumnHeaderMouseClick事件,自行实现排序逻辑:
// 在Form构造函数或Load事件中绑定事件 uiTaskGridView.ColumnHeaderMouseClick += UiTaskGridView_ColumnHeaderMouseClick; // 事件处理方法 private void UiTaskGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { var column = uiTaskGridView.Columns[e.ColumnIndex]; if (column.DataPropertyName != nameof(SimpleTask.Title)) return; var bindingList = tasksBinding.DataSource as BindingList<SimpleTask>; if (bindingList == null) return; // 转换为List进行排序 var list = bindingList.ToList(); if (column.HeaderCell.SortGlyphDirection == SortOrder.Ascending) { list.Sort((a, b) => string.Compare(b.Title, a.Title)); column.HeaderCell.SortGlyphDirection = SortOrder.Descending; } else { list.Sort((a, b) => string.Compare(a.Title, b.Title)); column.HeaderCell.SortGlyphDirection = SortOrder.Ascending; } // 更新BindingSource tasksBinding.DataSource = new BindingList<SimpleTask>(list); }
该方法需手动维护排序图标与逻辑,适合特殊场景下的自定义需求。
内容的提问来源于stack exchange,提问作者Chandernagor
相关产品推荐
相关产品推荐

