由于原生的BindingList并未提供排序功能,当DataGridView的数据源设为BindingList时,DataGridView的排序功能将不起使用。
以下是实现排序功能的SortableBindingList,需要用到拓展方法,通过构建表达式树去进行动态排序。
拓展方法如下:
namespace Common
{
public static class Utils
{
/// <summary>
/// 根据类实例的属性名进行排序
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="source"></param>
/// <param name="orderByProperty">属性名</param>
/// <param name="desc">降序:true,默认为升序:false</param>
/// <returns></returns>
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source,
string orderByProperty,
bool desc = false) where TEntity : class
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty) ?? throw new ArgumentException(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable),
command,
new Type[] {
type,
property.PropertyType
},
source.Expression,
Expression.Quote(orderByExpression));
return source.Provider.CreateQuery<TEntity>(resultExpression);
}
}
}
以下是SortableBindingList的代码:
using System.ComponentModel;
namespace IIIS_Inglewood.Common
{
/// <summary>
/// 可排序的BindingList
/// </summary>
/// <typeparam name="T">要素类</typeparam>
public class SortableBindingList<T> : BindingList<T>
where T : class
{
/// <summary>
/// 排序完成flag
/// </summary>
private bool isSorted;
/// <summary>
/// 排序方式
/// </summary>
private ListSortDirection sortDirection = ListSortDirection.Ascending;
/// <summary>
/// 被排序的属性的相关信息
/// </summary>
private PropertyDescriptor? sortProperty;
/// <summary>
///
/// </summary>
public SortableBindingList()
{
}
/// <summary>
///
/// </summary>
/// <param name="list"></param>
public SortableBindingList(IList<T> list)
: base(list)
{
}
/// <summary>
/// 是否支持排序(始终支持)
/// </summary>
protected override bool SupportsSortingCore
{
get { return true; }
}
/// <summary>
/// 排序完成flag
/// </summary>
protected override bool IsSortedCore
{
get { return this.isSorted; }
}
/// <summary>
/// 排序方式
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get { return this.sortDirection; }
}
/// <summary>
/// 被排序的属性的相关信息
/// </summary>
protected override PropertyDescriptor? SortPropertyCore
{
get { return this.sortProperty; }
}
/// <summary>
/// 删除排序信息
/// </summary>
protected override void RemoveSortCore()
{
this.sortDirection = ListSortDirection.Ascending;
this.sortProperty = null;
this.isSorted = false;
}
/// <summary>
/// 进行排序
/// </summary>
/// <param name="prop">排序项目</param>
/// <param name="direction">排序方式</param>
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
{
// 记录排序信息
this.sortProperty = prop;
this.sortDirection = direction;
// 项目一览
var list = Items as List<T>;
if (list == null)
{
return;
}
// 转成IQueryable,用拓展方法OrderBy进行排序
// PS:此处也可以用list.Sort的原生排序方式,但是连续排序多次的话会乱,具体原因暂不清楚
var newList = list.AsQueryable().OrderBy(prop.Name, sortDirection == ListSortDirection.Descending).ToList();
Items.Clear();
newList.ForEach(p => Items.Add(p));
// 排序完成
this.isSorted = true;
// 触发ListChanged事件
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
}
}