Follow up to Self Sorting GridView
(
Mar 25 2009 - 05:16:29 PM by
kiwipete) - [
print blog
post]
Some updates I made to
http://www.singingeels.com/Articles/Self_Sorting_GridView_with_LINQ_Expression_Trees.aspx
to allow Self Paging as well as sorting.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SingingEels.Web.UI.WebControls
{
// SelfSortingGridView - GridView from www.singingeels.com
// Updated to allow paging as well as sorting.
public class LinqGridView : GridView
{
private string _lastSortExpression;
private SortDirection _lastSortDirection;
protected override void OnSorting(GridViewSortEventArgs e)
{
this.Sorting += new GridViewSortEventHandler(this.SelfSortingGridView_Sorting);
base.OnSorting(e);
}
private void SelfSortingGridView_Sorting(object sender, GridViewSortEventArgs e)
{
this.PageIndex = 0; // Go back to the start of the list on sorting.
if (e.SortExpression == this._lastSortExpression && this._lastSortDirection == SortDirection.Ascending)
{
e.SortDirection = SortDirection.Descending;
}
else
{
e.SortDirection = SortDirection.Ascending;
}
SetupSorting(e.SortExpression, e.SortDirection);
this.DataBind();
this._lastSortExpression = e.SortExpression;
this._lastSortDirection = e.SortDirection;
}
protected override void OnPageIndexChanging(GridViewPageEventArgs eArgs)
{
this.PageIndexChanging += new GridViewPageEventHandler(this.SelfSortingGridView_PageIndexChanging);
base.OnPageIndexChanging(eArgs);
}
private void SelfSortingGridView_PageIndexChanging(object sender, GridViewPageEventArgs eArgs)
{
this.PageIndex = eArgs.NewPageIndex;
if (!string.IsNullOrEmpty(this._lastSortExpression))
SetupSorting(this._lastSortExpression, this._lastSortDirection);
this.DataBind();
}
private void SetupSorting(string sortExpression, SortDirection sortDirection)
{
IEnumerable _data = null;
// This will allow LINQ to SQL to pass the sorting on to the SQL Server itself.
if (this.DataSource is IQueryable)
{
_data = (IQueryable)this.DataSource;
}
else
{
DataSourceView dataView = this.GetData();
if (dataView == null)
{
// No data to sort.
return;
}
dataView.Select(this.SelectArguments, delegate(IEnumerable data)
{
_data = data;
});
if (_data == null)
{
// No data to sort.
return;
}
}
Type dataSourceType = _data.GetType();
Type dataItemType = typeof(object);
if (dataSourceType.HasElementType)
{
dataItemType = dataSourceType.GetElementType();
}
else if (dataSourceType.IsGenericType)
{
dataItemType = dataSourceType.GetGenericArguments()[0];
}
else if (_data is IEnumerable)
{
IEnumerator dataEnumerator = _data.GetEnumerator();
if (dataEnumerator.MoveNext() && dataEnumerator.Current != null)
{
dataItemType = dataEnumerator.Current.GetType();
}
}
var fieldType = dataItemType.GetProperty(sortExpression);
object sorterObject = null;
Type sorterType = null;
// We'll handle things like LINQ to SQL differently by passing the love
// on to the provider.
PropertyInfo property = dataItemType.GetProperty(sortExpression);
if (property != null)
{
sorterType = typeof(GenericSorter<,>).MakeGenericType(dataItemType, property.PropertyType);
sorterObject = Activator.CreateInstance(sorterType);
}
else
{
sorterType = typeof(LateBoundSorter);
sorterObject = Activator.CreateInstance(sorterType);
}
this.DataSource = sorterType.GetMethod("Sort", new Type[] { dataSourceType, typeof(string), typeof(SortDirection) })
.Invoke(sorterObject, new object[] { _data, sortExpression, sortDirection });
}
protected override object SaveControlState()
{
return new object[] { this._lastSortExpression, this._lastSortDirection, base.SaveControlState() };
}
protected override void LoadControlState(object savedState)
{
object[] stateItems = savedState as object[];
if (stateItems != null && stateItems.Length == 3)
{
this._lastSortExpression = (String) stateItems[0];
this._lastSortDirection = (SortDirection) stateItems[1];
base.LoadControlState(stateItems[2]);
}
else
{
base.LoadControlState(savedState);
}
}
}
public class GenericSorter<T, PT>
{
public IEnumerable<T> Sort(IEnumerable source, string sortExpression, SortDirection sortDirection)
{
var param = Expression.Parameter(typeof(T), "item");
var sortLambda = Expression.Lambda<Func<T, PT>>(Expression.Convert(Expression.Property(param, sortExpression), typeof(PT)), param);
if (sortDirection == SortDirection.Ascending)
{
return source.OfType<T>().AsQueryable<T>().OrderBy<T, PT>(sortLambda);
}
else
{
return source.OfType<T>().AsQueryable<T>().OrderByDescending<T, PT>(sortLambda);
}
}
public IEnumerable<T> Sort(IEnumerable<T> source, string sortExpression, SortDirection sortDirection)
{
var param = Expression.Parameter(typeof(T), "item");
var sortLambda = Expression.Lambda<Func<T, PT>>(Expression.Convert(Expression.Property(param, sortExpression), typeof(PT)), param);
if (sortDirection == SortDirection.Ascending)
{
return source.AsQueryable<T>().OrderBy<T, PT>(sortLambda);
}
else
{
return source.AsQueryable<T>().OrderByDescending<T, PT>(sortLambda);
}
}
}
public class LateBoundSorter
{
public IEnumerable Sort(IEnumerable source, string sortExpression, SortDirection sortDirection)
{
if (sortDirection == SortDirection.Ascending)
{
return source.OfType<object>().OrderBy(item =>
this.GetPropertyValue(item, sortExpression));
}
else
{
return source.OfType<object>().OrderByDescending(item =>
this.GetPropertyValue(item, sortExpression));
}
}
private object GetPropertyValue(object item, string propertyName)
{
return item.GetType().GetProperty(propertyName).GetValue(item, null);
}
}
}