In a web app, I needed paging and sorting to be done on a number of pages. I wanted something generic and looked at SortedBindingList and FilteredBindingList. After reading a couple of Rocky's posts and looking at the FilteredBindingList, it became apparent that using FilteredBindingList focuses on individual items rather than the state of the list. Therefore, I went a little different route.
I implemented a class that derives from IList<T> and also implements IReportTotalRowCount where T is your business object This little class first sorts the list handed to it and then applies the filtering based on the passed in SelectObjectArgs.
*** I believe that different grids will pass back differing information for the Sort Expression. The grid I am using (telerik) is clean, but I've seen others (Intersoft) that like to get cute if I remember correctly. Just a note of caution. Also, you could make this more generic to recognize when paging is not being requested by looking at SelectObjectArgs and operate accordingly.
The best part is the wiring of the SelectObjects event off the Csla Datasource control. Assuming I have a list of Customer objects (ReadOnly, BusinessObject, etc.) and a function that retrieves the Customer objects for the page (from db, session, viewstate, etc), the code looks like this:
CSLADataSource_SelectObject( object sender, Csla.Web.SelectObjectArgs e)
{
e.BusinessObject = new SortedAndPagedBindingList< Customer >(GetCustomerCollection(), e);
}
Now for the code:
/// <summary>
/// SortedAndPagedBindingList: This class is responsible for taking a List of 'TBase' and returning
/// a subset of items that are sorted and paged according to the Csla Datasource control. This control also
/// implements IReportTotalRowCount which is required to support paging within Csla.
/// </summary>
/// <typeparam name="TBase">The collection of Csla objects being sorted and paged</typeparam>
public class SortedAndPagedBindingList<TBase> : List<TBase>, Csla.Core.IReportTotalRowCount
{
/// <summary>
/// _totalRowCount: This retains the count of the initial list (as opposed to the trimmed down
/// result set. Used for paging purposes.
/// </summary>
private int _totalRowCount = -1;
/// <summary>
/// Constructor: This constructor builds out object list according to the Csla request.
/// </summary>
/// <param name="collection">The source list of all items to be considered.</param>
/// <param name="args">The paging and sorting parameters used against the incoming list</param>
public SortedAndPagedBindingList(IList<TBase> collection, Csla.Web.SelectObjectArgs args)
: base(args.MaximumRows)
{
// first, grab the total row count for reporting through the IReportTotalRowCount
_totalRowCount = collection.Count;
// next, we'll sort the list if requested.
Csla.SortedBindingList<TBase> sortedList = new Csla.SortedBindingList<TBase>(collection);
if (args.SortExpression.Length > 0)
sortedList.ApplySort(args.SortExpression, args.SortDirection);
// finally, we'll add the page of items requested by SelectObjectArgs
if (args.StartRowIndex > sortedList.Count - 1)
return;
int rowIndex = args.StartRowIndex;
while ((rowIndex - args.StartRowIndex) < args.MaximumRows && rowIndex < sortedList.Count)
this.Add(sortedList[rowIndex++]);
}
#region IReportTotalRowCount Members
/// <summary>
/// TotalRowCount - this property returns the total row count for the initial list that passed to the
/// constructor.
/// </summary>
int Csla.Core.IReportTotalRowCount.TotalRowCount
{
get { return _totalRowCount; }
}
#endregion
}