Ok, because I think all you clods have the same problem as a clod like me, the following post can really be helpfull, I think.
Remember the DataGrid in ASP.NET 1.x, and it's VirtualItemCount property ? If you wanted the DataGrid to display a custom pager row, you just had to set to "AllowCustomPaging" to true, bind a datasource to it, and supply a number to the VirtualItemCount property. Et voil� : the pager bar came 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 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 2 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 two : 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 a 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'RE 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 3 things :
- a method to supply the data (e.g. a datatable) (in our example, only 10 rows)
- a method to supply the total of numbers of the table (30.000)
- a method to supply the data with 2 parameters : one for setting the Start Row Index, 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 to 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 pagerrow !!!
Of course, the actual paging procedures are also to be written by you, but that's maybe for another post.
Good luck !
Erwin
PS Important remark : if you have cute little datatable of only 10 records, then also the GridView PageSize should be set to 10 !! (Duh!)
PS2 : 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 !