I'm trying to use a DataPager to do Server Side paging. Here is my code
<asp:DataPager ID="pgrFooBars" PagedControlID="lvFooBars"
QueryStringField="page" runat="server" >
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
ConfigureBlogPostListView();
}
private void ConfigureBlogPostListView()
{
int pageNum;
int.TryParse(Request.Params["page"], out pageNum);
int pageSize = 20;
PagedList<IFooBar> FooBars = FooService.GetPagedFooBars(
new PagingSettings(pageNum, pageSize));
ListViewPagedDataSource ds = new ListViewPagedDataSource();
ds.AllowServerPaging = true;
ds.DataSource = FooBars;
ds.MaximumRows = pageSize;
ds.StartRowIndex = pageNum;
//TotalCount is the total number of records in the entire set, not just those loaded.
ds.TotalRowCount = FooBars.TotalCount;
lvFooBars.DataSource = ds;
lvFooBars.DataBind();
pgrFooBars.PageSize = pageSize;
pgrFooBars.SetPageProperties(pageNum, FooBars.TotalCount, true);
}
PagedList comes from RobConery's useful post http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/.
The problem is that the DataPager appears to be using the Count property of the ListView to determine the total number of records, which in this case is 20. Somehow, it needs to know that there are 1,500, not 20 total records. The DataPager has a property TotalRowCount, but this is read-only.
I have never seen a DataPager example with Server Side paging, but assumed that it could do Server Side Paging, otherwise what good is the QueryStringField attribute?
I am aware that you can do a custom paging solution using methodology like the 4GuysFromRolla did here http://www.4guysfromrolla.com/articles/031506-1.aspx, but I'd first like to know if a solution with the DataPager is possible before creating a custom solution.
UPDATE The more I look at this, the more that I'm coming to the conclusion that this is not possible and that, unfortunately, the datapager is a control meant for small web sites only. What I want to do should really be quite simple if the control were built correctly. I want to be able to say
dpFooBars.TotalRowCountComputed = false;
dpFooBars.TotalRowCount = AnyNumberThatISoChoose;
I've been looking for some hack to accomplish the same thing, but it appears that the datapager's TotalRowCount is computed from the actual number of items in the datasource that it's bound to. It seems very odd to me that Microsoft would create a ListViewPagedDataSource() class and a DataPager at the same time and not have them work correctly together, but this appears to have been what has happened.
UPDATE 2 (AHA MOMENT?) It seems that it has been possible to do server side paging since .Net 2.0 by using an ObjectDataSource and customizing the SelectCountMethod(). I believe it should be possible to customize ObjectDataSource to suit my needs. Hmmm. I'm going away for the weekend, so it'll be a couple of days for me to see if this works. Stay tuned, true believers.
Exactly needed what you did - SQL server paging utilizing listview, datapager and linq data source. As you say TotalRowCount is readonly. There is also SetPageProperties method that can be used to set the total row count but that also didn't work for me.
However I managed to trick it this way. I have a dummy hidden listview with empty item template. The pager will be pointing at this dummy listview rather than the original listview. Then we need to bind the dummy listview to a dummy collection with the same number of items as in the original data source. This will ensure rendering the pager correctly. Here is the markup.
<asp:DataPager ID="pdPagerBottom" runat="server" PagedControlID="lvDummy" PageSize="5" QueryStringField="page">
<Fields>
<asp:NumericPagerField ButtonType="Link" RenderNonBreakingSpacesBetweenControls="true" NextPageText="Next" PreviousPageText="Previous" ButtonCount="40" />
</Fields>
</asp:DataPager>
<asp:ListView ID="lvDummy" runat="server" Visible="false">
<ItemTemplate></ItemTemplate>
</asp:ListView>
<asp:ListView ID="lvPropertyList" runat="server">...</asp:ListView>
and code behind
var datasourceQuery = context.Properties.OrderBy(x => x.PropertyID).Skip(pdPagerBottom.StartRowIndex).Take(pdPagerBottom.PageSize);
this.lvPropertyList.DataSource = datasourceQuery;
this.lvPropertyList.DataBind();
this.lvDummy.DataSource = new List<int>(Enumerable.Range(0, context.Properties.Count()));
this.lvDummy.DataBind();
Tested it with 100k records. Works a treat.