Friday, September 07, 2007

Support Sorting and Filtering for List<T> Collections

Many applications that display projections of LINQ to SQL queries in DataGridView controls require sorting on a programmatic or user-selectable column and with a specified sort direction. Some projects also need to programmatically filter the DataGridView's or other data-bound control's BindingSource component.

LINQ to SQL DataContext.DataTable objects offer a new GetNewBindingList() method that produces an IBindingList<T> object to supply a sortable BindingList.DataSource or DataGridView.DataSource property value. However IBindingList<T> doesn't support filtering; for that feature you need an IBindingListView<T> object.

Applying the IEnumerable<T>.ToList(), IQueryable<T>.ToList() or ISingleResult<T>.ToList() method returns a generic List<T> object that doesn't support sorting or filtering. All IBindingListView<T> objects support filtering and sorting; some support advanced sorting on multiple columns. Implementing the IBindingListView interface isn't a piece of cake, as demonstrated by the few working examples you'll find on the Web.

In searching for a wrapper for List<T> objects that would provide advanced (multi-column) sorting and filtering, I ran across Andrew Davey's BindingListView (blw) project on SourceForge, where it's offered under a BSD license. Andrew's an independent .NET developer in Bristol, UK and a student at the University of Warwick. He claimed in August 2006 BindingListView speedy sorting blog entry that blw sorts faster than the DataGridView.

I downloaded the C# 2.0 source code and did the following to give the BindingListView<T> class a test drive with a BindingSource component and DataGridView control populated by a List<T> object from a LINQ query:

  1. Added it as a project to my DynamicSQLTestHarness.sln LINQ to SQL performance analysis project.
  2. Created a project reference for the VB 9.0 WinForm client (see screen capture below).
  3. Added an Imports Equin.ApplicationFramework directive.
  4. Added a blvOrders = New BindingListView(Of Order)(lstOrders) statement to create a BindingListView(Of Order) object from the List(Of Order) object.
  5. Supplied an anonymous method to deliver the filter expression.
  6. Provided an SQL ORDER BY clause to sort multiple columns.

Andrew hadn't LINQ-enabled blw, so the BindingListView(Of Order)class threw exceptions when attempting to create a BindingListView(Of Order_Detail) object from each Order_Details EntitySet. A simple hack that tests for the presence of the ` character in the Equin.ApplicationFramework.BindingListView`1[DynamicSQLTestHarness.Order_Detail] typeName variable and returns null instead of the unwanted instance solved that problem.

Click image for full-size capture.

The screen capture shows the test harness after opening the form and loading the Customers, Orders, and Order_Details grids. Notice that the OrdersBindingSource reports that Advanced Sorting and Filtering is supported.


Tim Elvidge said...

Is there some sample source code to go with this article. I have downloaded the equi.applicationframework and installed it but i get class errors could you post the hack??