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:
- 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. - 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:
internal class MyTableAdapter
{
private DataTable _dt;
private int _vic;
public MyTableAdapter(DataTable dt, int vic)
{
_dt = dt;
_vic = vic;
}
public DataTable GetData()
{
return _dt;
}
public int VirtualItemCount()
{
return _vic;
}
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
.
internal class MyGridViewFiller
{
private DataTable _dt;
private int _vic;
private Page _page;
private string _id;
public void CreateCuteLittleTable(Page Page, string GridViewID)
{
_dt =
_vic =
_page = Page;
_id = GridViewID
FillGridView()
}
public void FillGridView()
{
GridView gv = (GridView)_page.FindControl(_id);
ObjectDataSource ods = new ObjectDataSource();
ods.ID = "ods" + _id;
ods.EnablePaging = gv.AllowPaging;
ods.TypeName = "MyTableAdapter";
ods.SelectMethod = "GetData";
ods.SelectCountMethod = "VirtualItemCount";
ods.StartRowIndexParameterName = "startRow";
ods.MaximumRowsParameterName = "maxRows";
ods.EnableViewState = false;
ods.ObjectCreating +=
new ObjectDataSourceObjectEventHandler(ods_ObjectCreating);
gv.DataSource = ods;
gv.DataBind();
}
private void ods_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = new MyTableAdapter(_dt, _vic);
}
}
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!