Way 2 Web

Web development tips


 
Custom Pager

Introduction

On the same page

ASP .Net offers some pretty sleek short cuts, in particular the DataGrid and its relatives. The control effortlessly displays your data source in a neat tabular format complete with paging. Quick, simple and customisable.

However, this comes at a cost: performance.

The DataGrid retrieves the entire data set each trip to the server, even though it only displays one page of that set. For large data sets, this can significantly slow page load and over-burden the poor database.

This problem isn't new. Databases such as MySql and, lately, Sql Server allow you to specify the rows that you want within a set of data; onyl these rows are retrieved. The catch: the DataGrid control automatic paging becomes useless since it thinks that the retrieved rows are all she wrote.

This is where the Custom Pager steps in. It provides paging for the efficient data retrieval method mentioned above.

API

Tag

<WowoControls:PagingNav runat="server" ID="PagingNav1" 
    PagingStyle="Both" 
    OnPageChanged="Pager_PageChanged" 
    .../>
PagingStyle
Values: Words, Numbers, Both
OnPageChanged
The event handler to call when the page changes. This is discussed in more detail below.
...
The other attributes refer to text and CSS class values and are fairly self-explanatory. Not all of them are listed above.
[Top of page]

Demo

Both: Words and Numbers

This example displays both paging rows: Words and Numbers.

The data is generated programmatically without accessing a database, but the principle is the same.

Column1Column2
row 1col2
row 2col2
row 3col2
row 4col2
row 5col2
row 6col2
row 7col2
row 8col2
row 9col2
row 10col2
FirstPreviouspage 1 of 1,001NextLast
[Top of page]

Code

ASP

<asp:DataGrid runat="Server" ID="grid" EnableViewState="true" 
    AllowCustomPaging="true" AutoGenerateColumns="true"
    PageSize="10" CssClass="grid-table"></asp:DataGrid>
           
    <WowoControls:PagingNav runat="server" ID="pager" PagingStyle="Both" 
                    OnPageChanged="Pager_PageChanged" 
                    CssClass="paging-container" 
                    NumberRowCssClass="paging-row"
                    NumberLinkCssClass="link" NumberCurrentPageCssClass="thisPage"
                    WordRowCssClass="paging-row" 
                    WordFirstLinksCssClass="first-links" WordLastLinksCssClass="last-links" 
                    WordResultsMessageCssClass="mess"
                    WordPreviousLinkCssClass="link" WordNextLinkCssClass="link"
                    WordFirstLinkCssClass="link" WordLastLinkCssClass="link"/>

Code Behind

protected void Page_Load(object sender, EventArgs e) {
    if (!Page.IsPostBack) {
        BindData();
    }
}

const long TOTAL_ROWS = 10005;
protected void BindData() {
    //get data (in place of DB call, we create a generic list of objects)
    //in practice (MySql example), construct query ending:
    //  ' LIMIT <startRow>, <pageSize>'
    long startRow = ((pager.CurrentPage - 1) * grid.PageSize) + 1;
    List data = GetData(startRow, grid.PageSize);
    //init pager
    pager.PageSize = grid.PageSize;
    pager.ResultsCount = TOTAL_ROWS; //in practice, TOTAL_ROWS is replaced with 
                                     //count(*) of SQL results, returned as  a field or 
                                     //stored procedure return value
    
    //connect grid to data
    grid.DataSource = data;
    grid.DataBind();
}
protected void Pager_PageChanged(object sender, EventArgs e) {
    BindData();
}

In short, wrap your data binding in a method such as GetData() and be careful to:

  • Inside the method, give values for properties PageSize and ResultsCount of the paging control.
  • Call it on page load (in Page_Load())

Also, provide an event handler such as Pager_PageChanged() that calls this binding method. This will be called by the Paging Control when page number changes.

We have left out the method GetData(). Replace it with your data access layer functionality.

Also, note that we use a hardcoded ResultsCount value for demo purposes. In the "real world", you will use the number of total records available, returned either as a stored procedure return value or a field in the return data set. This value must be available for at least the first page load. It will be remembered by the control in future page changes. (Therefore, only "overwrite" the value of ResultsCount when the value is accurate.)

CSS

.grid-table, paging-container {
    width: 400px;
    display: block;
} 
.paging-row {
    padding-top: 5px;
    display: block;
    clear:left;
}
.mess {
display: block;
    float: left;
    text-align: center;
    width: 200px;
    color: red;
}
.first-links{
    float:left;
}
.last-links {
    float:left;
}
.link, .thisPage {
    padding: 5px;
}
.thisPage {
    text-decoration: none;
    color: black;
}

Files

[Top of page]