ASP.NET是一个非常强大且广泛使用的 Web 应用程序框架,它提供了丰富的控件和功能来简化开发过程。其中,GridView控件是用于显示和操作数据的常用工具。尽管它功能强大,但在实现排序功能时存在一些限制。本文将介绍如何克服这些限制,实现更加灵活和动态的排序功能。
假设有一个 Person 类型的序列,希望将其绑定到GridView控件,并允许用户通过点击相应的列头来排序数据。Person 类定义如下:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
通常情况下,可以通过硬编码的方式来指定排序表达式和排序方向。但是,这种方法的缺点是不够灵活,所有的属性和排序方向都是硬编码的。更好的方法是动态地创建这些排序逻辑。
为了实现动态排序,可以将逻辑封装到几个专门的类中。第一个类是 SortExpressionConverter,它将 SortDirection 转换为一个函数,该函数接受一个序列和一个函数,并返回按该对象属性排序后的序列。
public static class SortExpressionConverter<T>
{
private static IDictionary<SortDirection, ISortExpression> expressions = new Dictionary<SortDirection, ISortExpression>
{
{ SortDirection.Ascending, new OrderByAscendingSortExpression() },
{ SortDirection.Descending, new OrderByDescendingSortExpression() }
};
interface ISortExpression
{
Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression();
}
class OrderByAscendingSortExpression : ISortExpression
{
public Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression()
{
return (c, f) => c.OrderBy(f);
}
}
class OrderByDescendingSortExpression : ISortExpression
{
public Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> GetExpression()
{
return (c, f) => c.OrderByDescending(f);
}
}
public static Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> Convert(SortDirection direction)
{
ISortExpression sortExpression = expressions[direction];
return sortExpression.GetExpression();
}
}
第二个类是 SortLambdaBuilder,它构建一个 lambda 表达式,并返回底层的 lambda 函数:
public static class SortLambdaBuilder<T>
{
public static Func<T, object> Build(string columnName, SortDirection direction)
{
// x
ParameterExpression param = Expression.Parameter(typeof(T), "x");
// x.ColumnName1.ColumnName2
Expression property = columnName.Split('.').Aggregate<string, Expression>((param, c, m) => Expression.Property(c, m));
// x => x.ColumnName1.ColumnName2
Expression<Func<T, object>> lambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof(object)), param);
Func<T, object> func = lambda.Compile();
return func;
}
}
最后,将这些类封装到一个扩展方法中:
public static class CollectionExtensions
{
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> collection, string columnName, SortDirection direction)
{
Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> expression = SortExpressionConverter<T>.Convert(direction);
Func<T, object> lambda = SortLambdaBuilder<T>.Build(columnName, direction);
IEnumerable<T> sorted = expression(collection, lambda);
return sorted;
}
}
protected void gridPersons_Sorting(object sender, GridViewSortEventArgs e)
{
IEnumerable<Person> persons = GetPersons();
persons = persons.OrderBy(e.SortExpression, e.SortDirection);
gridPersons.DataSource = persons.ToArray();
gridPersons.DataBind();
}