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

Custom Paging and the GridView in ASP.NET 2.0 - You'll thank me for this!

3.18/5 (42 votes)
3 Mar 2007CPOL4 min read 1  
How to programmatically bind a GridView to a DataSource and let it show a pager.

Introduction

OK, because I think all you clods have the same problem as a clod like me, the following post can really be helpful, I think.

Remember the DataGrid in ASP.NET 1.x, and its VirtualItemCount property? If you wanted the DataGrid to display a custom pager row, you just had to set AllowCustomPaging to true, bind a data source to it, and supply a number to the VirtualItemCount property. Et voilĂ : the pager bar comes up automatically! Magic!

With ASP.NET 2.0, a new kid was in town: the GridView. Great stuff !! But, wait a minute, it isn't that easy to display a custom pager row! I looked and looked and searched and read quite some stuff, and finally, I came up with the following solution. Now, I could very well keep this just to myself, but since I'm such a nice person, I'll share it with all you clowns..

Suppose that you have the following situation:

  • You have a GridView, and you want only 10 records to display at a time.
  • You have a table which contains 30,000 records.
  • You don't want to use the default paging of the GridView, because this will retrieve all 30,000 records at every round trip.
  • You have figured out a way to retrieve only 10 records at a time. (I'm not going into the details of this, maybe in a later post, I found some great stuff to do just that!)

The only thing you need is to have the GridView display a pager row. And there, you're stuck. Because the GridView does not have a VirtualItemCount property, it only has a PageCount property, but that's read only!

A solution could be to do all the work declaratively at design time. In fact, all the tutorials and posts that you'll read show you how to do this declaratively, with the help of a ObjectDataSource and a TableAdapter. But that is at design time!

What if you need to bind the GridView at run-time, i.e. programmatically? That's where the real problem lies!

In order to solve this problem, you have to know two things:

  • The ObjectDataSource (=ODS) needs to have the name of a class that will handle the data requests. When you do this by declaration, it's the TableAdapter that takes care of that. So, part of the solution is to create our own TableAdapter!
  • On the other hand, the ODS at run-time creates an instance of that class with a parameterless constructor. You can shout "Yikes!" twice here: first, because the data-handling object can not be instantiated (constructed) with any parameters, and second, it can not be accessed because it's shielded in the ODS.

So, how can you feed your precious 10-record table to that data-object? Well, you can't...

Unless....

You do the following things:

  1. Create your own TableAdapter that takes care of providing the data. Don't worry, if you're only interested in displaying records, it's done in a snap.
  2. Create an event-handler that takes control over what kind of datasource object is created and handed over to the ODS. Again, this only takes some lines of code.

And, you are done!

OK, let's get down to it.

First, let's create our own TableAdapter. When it's only for data-displaying, our TableAdapter should contain only three things:

  • A method to supply the data (e.g., a DataTable) (in our example, only 10 rows)
  • A method to supply the total number of rows in the table (30,000)
  • A method to supply the data with two parameters: one for setting the start-row-index, and the other for setting the maximum-rows. (Actually, I'm not going to do anything with this, because I already have my DataTable with the right records! Still, the method has to be there!)

Also, I'm going to write a constructor of this class that will take as parameters our cute little DataTable and the total number of rows, which I'll will call "VirtualItemCount" (to salute the earlier DataGrid).

This is how it could look like:

C#
internal class MyTableAdapter
{
     private DataTable _dt;
     private int _vic; 

     //this is the constructor that takes as parameters a cute little datatable
     // with the right 10 records, an an integer vic = virtualitemcount
     public MyTableAdapter(DataTable dt, int vic)
     {
        _dt = dt;
        _vic = vic;
     } 

     //this returns the datatable (10 records)
     public DataTable GetData()
     {
        return _dt;
     } 

     //this returns the total number of records in the table (30.000)
     public int VirtualItemCount()
     {
        return _vic;
     } 

     //this also returns the datatable (10 records)
     //but the ODS needs it for paging purposes
     public DataTable GetData(int startRow, int maxRows)
     {
         return _dt;
     }
}

The next thing we'll do is create a class which will handle the creation of a DataTable, and hand it over to another function to feed the GridView.

C#
internal class MyGridViewFiller
{
     //these fields are for storing the cute little
     //datatable and the virtualitemcount
     private DataTable _dt;
     private int _vic; 

     //these fields are for storing the calling page and the GridViewID
     private Page _page;
     private string _id; 

     public void CreateCuteLittleTable(Page Page, string GridViewID)
     { 
        //here you create your cute little datatable
        //and also you calculate the total number of rows 
        _dt = //some code to create the 10-row DataTable
        _vic = //some code to calculate the total rows of the table (30.000) 

        //let's also store the page and the gridviewid
        _page = Page;
        _id = GridViewID 

        //call the GridView filler
        FillGridView()
      } 

     public void FillGridView()
     { 
         //First let's make an GridView object that hold the GridView 
         GridView gv = (GridView)_page.FindControl(_id); 

         //Then create an ObjectDateSource object programmatically
         ObjectDataSource ods = new ObjectDataSource(); 

         //setting the necessary properties 
         //(these will interact with our TableAdapter !)
         ods.ID = "ods" + _id; 

         //the paging of ODS depends on the paging of the GridView
         ods.EnablePaging = gv.AllowPaging;
         //be sure to prefix the namespace of your application
         //!!! e.g. MyApp.MyTableAdapter
         ods.TypeName = "MyTableAdapter";
         ods.SelectMethod = "GetData"; 
         ods.SelectCountMethod = "VirtualItemCount";
         ods.StartRowIndexParameterName = "startRow";
         ods.MaximumRowsParameterName = "maxRows";
         ods.EnableViewState = false;

         //HERE IS THE TRICK !!!
         //In stead of calling the parameterless 
         //constructor of our TableAdapter, I'm going 
         //to hook up on the ods.ObjectCreating event
         //to supply my own TableAdapter (WITH constructor parameters)
         //the following line is the "hook up" declaration 

         ods.ObjectCreating += 
           new ObjectDataSourceObjectEventHandler(ods_ObjectCreating); 

         //this means that at the object creating event, the CLR is going
         //to jump to my event handler (ods_ObjectCreating) 
         //after that, we only need to bind the ODS to the GridView 

         gv.DataSource = ods;
         gv.DataBind(); 

        // AND THAT's ALL FOLKS !!!
      }

      //this is the ObjectCreating event handler
      private void ods_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
      {
        //calling a "parametered" constructor of my own 
        //TableAdapter and passing it to the ObjectInstance property 
        e.ObjectInstance = new MyTableAdapter(_dt, _vic); 

        //and that'all there's to it !!
      } 
}

If you go very slowly through the code, you will find it very simple and straightforward. And best of all: you have the GridView display the pager row!!! Of course, the actual paging procedures are also to be written by you, but that's maybe for another post.

Good luck!

Important remark: If you have a cute little DataTable of only 10 records, then also the GridView's PageSize should be set to 10 (duh!).

Remark 2: Hmmm, I noticed that you don't give high voting points... You could leave me a comment to point out what could be better? Thanks!

License

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