Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

DeleGrid: Pagination for the Delegates

3.80/5 (4 votes)
18 Dec 2007CPOL3 min read 2   182  
The DeleGrid is a control derived from the ASP.NET GridView that delegates its data retrieval back out of the control.

This article is also maintained on my blog.

Introducing the DeleGrid

The DeleGrid is a control derived from the ASP.NET GridView, that delegates its data retrieval back out of the control. This allows the developer full control over the records that are retrieved, thus allowing proper paging to be implemented using whatever collection type is preferred.

Background

The DeleGrid came about because I wanted a nice way of implementing paging using NHibernate without having the grid know about it. I really didn't want NHibernate to leave my data layer, so I needed a nice way of the grid calling my DAL with the paging parameters.

Using the DeleGrid

After getting the source or assembly and doing the usual song-and-dance, add a reference to the control to your page:

ASP.NET
<%@ Register Assembly="JAGregory.Controls.DeleGrid" 
    Namespace="JAGregory.Controls" TagPrefix="jag" %>

Then create an instance of the control, turning the paging on and setting the correct page size:

HTML
<jag:DeleGrid ID="grid" runat="server" AllowPaging="true" PageSize="4" />

Now you have a control set up, however it still won't bind correctly. So, you need to attach the event handlers in the code-behind.

C#
protected override void OnInit(EventArgs eventArgs)
{
  base.OnInit(eventArgs);

  grid.TotalRecordCountRequest += delegate {
    // code to get total
  };
}

Starting with the TotalRecordCountRequest, this event is raised when the grid needs to know how many records in total your grid is going to be displaying. This number is the cumulative count of all the pages. I'm going to use a simple repository pattern to factor away my DAL logic.

The OnInit method is now:

C#
protected override void OnInit(EventArgs eventArgs)
{
  base.OnInit(eventArgs);

  ProductRepository repos = new ProductRepository();

  grid.TotalRecordCountRequest += delegate {
    return repos.GetTotal();
  };
}

Now your grid knows how many records it has overall, however we still haven't told it how to actually get the data. Now we need to put the code in the PageDataRequest handler. This event is raised when the grid needs a new page of data. This will get called once on initial data-bind, then again every time you change the page (or sort etc.).

The OnInit method is now:

C#
protected override void OnInit(EventArgs eventArgs)
{
  base.OnInit(eventArgs);

  ProductRepository repos = new ProductRepository();

  grid.TotalRecordCountRequest += delegate {
    return repos.GetTotal();
  };
  grid.PageDataRequest += delegate(object sender, DataRequestEventArgs e) {
    return repos.GetRange(e.Start, e.Size);
  };
}

The event-handler receives an instance of DataRequestEventArgs, which contains the start index of the current page of data, and the number of records in a page. It also contains a SortField and SortDirection, used when sorting is enabled on the grid. However, we aren't utilising them in this example.

Finally we just need to bind the grid on page load. We don't re-bind the grid on post-back, since it is handled internally in the DeleGrid.

C#
protected override void OnLoad(EventArgs eventArgs)
{
  base.OnLoad(eventArgs);

  if (!IsPostBack)
    grid.DataBind();
}

That’s all there is to it!

You don't need to use delegates, the normal event-handler syntax is fine (and probably preferred for larger examples). I just did it this way for brevity’s sake.

Further Reading...

Testing

I've written a small number of tests that cover the implementation of the grid as best as I can. There was only so-far I was willing to go to test the control, as it’s heavily tied to the ASP.NET implementation. This can get pretty messy for testing without using something like NUnitASP, which was a little too much for one control. I've got coverage of about 85% of the code, which I'd say is pretty reasonable anyway.

Sorting

As mentioned above, you can implement sorting in your handlers by accessing the SortField and SortDirection properties of the event arguments.

DeleGrid.AlwaysRequestTotal Property

By default, the DeleGrid only requests the total number of records on the initial data-bind. However if you see this as being a problem (such as with rapidly changing data-sets), you may want to set this property to true so it refreshes the total on every data-bind.

Open Source

The DeleGrid is open-source under the new BSD License. Read the license for what you're allowed to do.

The source is also accessible from Subversion here (using user jagregory-read-only).

History

  • 1.0 - Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)