Click here to Skip to main content
15,867,686 members
Articles / Web Development / ASP.NET
Article

Custom Paging with User Control

Rate me:
Please Sign up or sign in to vote.
4.32/5 (18 votes)
16 Mar 20045 min read 159.2K   2.7K   64   29
Promote Code Reuse by Using a User Control to Do Custom Paging

Sample Image - PagingUserControl.jpg

Introduction

It's not hard to find code examples on how to do custom paging in ASP.NET, but I haven't found any good examples on using a user control to do so. This example shows you how to construct your own user control to perform custom paging; thus, promote code reuse by dropping the control on every page that needs the same functionality.

The user control shown in this example uses several events to control the page navigation, if you're not so familiar with how events/delegates work you'll probably have to get some reference on the topic first.

This solution also requires writing stored procedures that return pieces of data to be display on each page. I borrowed the idea from Zek3vil in his article - Custom Data Paging in ASP.NET (http://www.codeproject.com/aspnet/custompaging.asp?target=custom%7Cpaging). Basically, he used a temp table with an ID column that has the IDENTITY and PRIMARY KEY attribute to hold the returned data. Although the example was written in T-SQL, the same concept could be implemented in PL/SQL as well.

To make it simple, I decided to use the employee table in pubs database on MS SQL Server. Let's start by looking at the stored procedure:

Creating the Stored Procedure

SQL
CREATE PROCEDURE Get_Employees( @CurrentPage int,
     @PageSize int,
     @TotalRecords int OUTPUT)

AS

-- Turn off count return.
Set NoCount On

-- Declare variables.
Declare @FirstRec int
Declare @LastRec int

-- Initialize variables.
Set @FirstRec = (@CurrentPage - 1) * @PageSize
Set @LastRec = (@CurrentPage * @PageSize + 1)

-- Create a temp table to hold the current page of data
-- Add an ID column to count the records
Create Table #TempTable
(
 EmpId int IDENTITY PRIMARY KEY,
 fname varchar(20),
 lname varchar(30),
 pub_id char(4),
 hire_date datetime
)

--Fill the temp table with the reminders
Insert Into #TempTable 
(
 fname,
 lname,
 pub_id,
 hire_date
)
Select  fname,
  lname,
  pub_id,
  hire_date
From  employee
Order By lname

--Select one page of data based on the record numbers above
Select fname,
 lname,
 pub_id,
 hire_date
From #TempTable
Where EmpId > @FirstRec 
And EmpId < @LastRec

--Return the total number of records available as an output parameter
Select @TotalRecords = Count(*)
From #TempTable
GO

The stored procedure has 2 input and 1 output parameter - @CurrentPage is the current page number and should be greater than 0; @PageSize determines how many records to display on each page; @TotalRecords returns the number of records in total, which is also being used to calculate the total number of pages.

Next, let's talk about the meat - the user control:

Paging User Control

ASP.NET
<table width="100%">

    <tr>

        <td>(Page

            <asp:label id="lblCurrentPage" Runat="server"></asp:label>of

            <asp:label id="lblTotalPages" Runat="server"></asp:label>)

        </td>

        <td valign="top" align="right">

            Page

            <asp:DropDownList id="ddPage" runat="server"

                AutoPostBack="true"></asp:DropDownList>

        </td> 

        <td align="right"> 

            <asp:imagebutton id="btnFirst" Runat="server" Enabled="false" 

                ImageUrl="Images/NavFirstPageDisabled.gif" /> 

            <asp::imagebutton id="btnPrevious" Runat="server" Enabled="false"

               ImageUrl="Images/NavPreviousPageDisabled.gif" /> 

            <asp:imagebutton id="btnNext" Runat="server" Enabled="false"

               ImageUrl="Images/NavNextPageDisabled.gif" /> 

            <asp:imagebutton id="btnLast" Runat="server" Enabled="false" 

               ImageUrl="Images/NavLastPageDisabled.gif" /> 

        </td> 

    </tr>

</table>

The user control consists of 3 parts - labels that show something like "(Page 1 of 10)," a dropdown listbox that allows you to jump from page to page and 4 VCR-type buttons to navigate between First, Previous, Next and Last page.

There are some limitations on ASP.NET image buttons that hopefully will be improved in the next release. First, the image doesn't grey out when the button is disabled. Hence, we'll have to explicitly change the ImageUrl attribute when we enable/disable the button. Second, the mouse cursor remains the same (index finger) regardless of the button state. I didn't do anything to correct this problem in my code but it's a good exercise for you to figure out.

Now let's look at the code behind:

C#
//public deletgates

public delegate void FirstPageEventHandler(object sender, 

    DataNavigatorEventArgs e);

public delegate void LastPageEventHandler(object sender, 

    DataNavigatorEventArgs e);

public delegate void PreviousPageEventHandler(object sender, 

    DataNavigatorEventArgs e);

public delegate void NextPageEventHandler(object sender,

    DataNavigatorEventArgs e);

public delegate void PageChangedEventHandler(object sender,

    DataNavigatorEventArgs e);

Since each VCR-type button and the dropdown listbox has its own event to be linked to, we have to first declare all the public delegates. Notice that we have our own custom event argument type (DataNavigatorEventArgs) because we need to keep track of the current page and total page number each time we navigate between pages.

Here's the DataNavigatorEventArgs class:

C#
public class DataNavigatorEventArgs : EventArgs

{

    private int m_iCurrentPage;

    private int m_iTotalPages;

    public DataNavigatorEventArgs()

    {

    }

    public int CurrentPage

    {

        get { return m_iCurrentPage; }

        set { m_iCurrentPage = value; }

    }

    public int TotalPages

    {

        get { return m_iTotalPages; }

        set { m_iTotalPages = value; }

    }

} 

Then, we declare all public events that are hooked up with those delegates:

C#
//public events

public event FirstPageEventHandler FirstPage;

public event LastPageEventHandler LastPage;

public event PreviousPageEventHandler PreviousPage;

public event NextPageEventHandler NextPage;

public event PageChangedEventHandler PageChanged;

For those image buttons, we have to forward the Click event to our declared delegates. We do this by the following code inside the InitializeComponent() function:

C#
private void InitializeComponent()

{

    this.btnPrevious.Click += new System.Web.UI.ImageClickEventHandler

        (this.OnPreviousPageButton);

    this.btnNext.Click += new System.Web.UI.ImageClickEventHandler

        (this.OnNextPageButton);

    this.btnFirst.Click += new System.Web.UI.ImageClickEventHandler

        (this.OnFirstPageButton);

    this.btnLast.Click += new System.Web.UI.ImageClickEventHandler

        (this.OnLastPageButton);

    this.ddPage.SelectedIndexChanged += new EventHandler

        (this.OnPageChangedButton);

    this.Load += new System.EventHandler(this.Page_Load);

}

Now let's take the Next button for example, we forward the Click event to this.OnNextPageButton() function. Here's how that function looks like:

C#
protected void OnNextPageButton(object sender, ImageClickEventArgs e)

{

    DataNavigatorEventArgs args = new DataNavigatorEventArgs();

    args.CurrentPage = int.Parse(lblCurrentPage.Text);

    args.TotalPages = int.Parse(lblTotalPages.Text);

 

    SetDropDownPageNumber(args.CurrentPage + 1);

 

    OnNextPage(args);

}

We instantiate the DataNavigatorEventArgs object, assign its values from the labels on the user control, call the SetDropDownPageNumber() to set the correct page number displayed in the dropdown listbox, and most importantly, forward the call to OnNextPage() to raise the event by invoking delegates.

C#
protected virtual void OnNextPage(DataNavigatorEventArgs args)

{

    if (NextPage != null)

    {

        // Invoke the delegates.

        NextPage(this, args);

    }

}

Notice the difference in declaration and signature between OnNextPageButton() and OnNextPage(). (Note: the name of your function that raises the event has to be OnEventName such as OnNextPage).

Here's the SetDropDownPageNumber() function that sets the page number for the dropdown listbox:

C#
private void SetDropDownPageNumber(int iCurrentPage)

{

     if (ddPage.Items.Count > 0)

        // since SelectedIndex is 0-based, we have to

        // take the current page number and minus 1

        ddPage.SelectedIndex = iCurrentPage - 1;

}

The user control also has public get/set properties that keep track of the current page number, total page number, each image button's state and its image URL. These properties will be used on the ASP.NET page where the control resides.

Using the Control

To use the control, just drag it from the Solution Explorer and drop it on your ASP.NET page. Here's the HTML of the page:

ASP.NET
<form id="Form1" method="post" runat="server">

    <table width="100%"> 

        <tr> 

            <td> 

                <asp:datagrid id="dgEmp" runat="server"

                    EnableViewState="false"

                    AlternatingItemStyle-BackColor="Silver"

                    AllowCustomPaging="true"

                    Width="100%" HeaderStyle-BackColor="#6633ff"

                    HeaderStyle-ForeColor="#ffffff"

                    HeaderStyle-Font-Bold="true"></asp:datagrid>

            </td>

        </tr> 

        <tr> 

            <td><uc1:datanavigator id="ucDataNavigator"

                       runat="server"></uc1:datanavigator>

            </td> 

        </tr> 

    </table>

</form>

Now let's take a look at the code behind. First, don't forget to hook up all the event handlers for our control:

C#
private void InitializeComponent()

{

    this.ucDataNavigator.FirstPage += new FirstPageEventHandler

        (this.FirstPage);

    this.ucDataNavigator.PreviousPage += new PreviousPageEventHandler

        (this.PreviousPage); 

    this.ucDataNavigator.NextPage += new NextPageEventHandler

        (this.NextPage); 

    this.ucDataNavigator.LastPage += new LastPageEventHandler

        (this.LastPage); 

    this.ucDataNavigator.PageChanged += new PageChangedEventHandler

        (this.PageChanged); 

    this.Load += new System.EventHandler(this.Page_Load); 

    this.Init += new EventHandler(this.Page_Init);

}

Remember previously we made the Click event of the Next image button raise the NextPage event? Here we get to define our NextPage event handler:

C#
protected void NextPage(object sender, DataNavigatorEventArgs e)

{

    if (e.CurrentPage <= e.TotalPages)

    {

        // Increment the current page index.

       ucDataNavigator.CurrentPage++;

 

       // Get the data for the DataGrid.

       BindGrid();

 

       EnableDisableButtons(e.TotalPages);

    }

}

Here we first increment the current page index then retrieve the data for the DataGrid, finally, we call EnableDisableButtons() to control the state and image of each VCR-type image button.

Note that I use Page_Init() method above to intialize the CurrentPage property on the user control to 1 since this only has to be done once.

C#
private void Page_Init(object sender, System.EventArgs e)

{

    ucDataNavigator.CurrentPage = 1;

}

Inside the BindGrid() method I used the following logic to calculate the number of pages:

C#
if ((totalCount % PAGE_SIZE) == 0)

    ucDataNavigator.TotalPages = totalCount/PAGE_SIZE;

else

    ucDataNavigator.TotalPages = (totalCount/PAGE_SIZE) + 1;

totalCount's value is from the output parameter of the stored procedure and PAGE_SIZE is a constant defined as 10 in my code. So another good exercise for you to do is to externalize the PAGE_SIZE constant; i.e., instead of hard-coding it, make it table-driven or store the value in a configuration file.

Conclusion

The biggest advantage of using user controls on your ASP.NET pages is code-reuse. This article shows you how you can utilize this concept to avoid writing repeated code. To make it one step further, instead of a user control, you could write a custom control to do this so that it'd be even easier to reuse your code.

Next time I'll show you how to add sorting functionality in our paging user control. Have fun!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
Linus has more than 10 years of experience in designing and implementing enterprise scale applications. He is a seasoned architect in both J2EE and Microsoft technologies. He is also a Microsoft Certified Solution Developer for .NET.

Comments and Discussions

 
QuestionClicking on next reload parent as well as all the user control page. Pin
Member 1131376424-Nov-17 0:12
Member 1131376424-Nov-17 0:12 
GeneralGot error in global.aspx file Pin
sreelink12-Nov-10 4:37
sreelink12-Nov-10 4:37 
GeneralMy vote of 3 Pin
sreelink12-Nov-10 4:32
sreelink12-Nov-10 4:32 
QuestionHow To Fix Datagrid Pager Position Irrespective of Number of Records Returned Pin
elizas14-Apr-10 23:46
elizas14-Apr-10 23:46 
Datagrid PageSize = 15 and 75 records are returned from DB, then pager will show 5 pages. If 70 records are returned, pager will show 5 pages and if the 4th ( last page) page is clicked pager will move upwards, i.e pager will take the position just after the 10th record and not at the end of the datagrid as in other pages.

If you want to fix that pager, add a css to pagerstyle.

<PagerStyle CssClass="pager" Wrap="True" Mode="NumericPages" Position="Bottom"></PagerStyle>

Pager rendered as TD.

CSS

TR.pager TD
{
left: 0px;
width: 958px;
border-right-style: solid;
position: absolute;
top: 380px;
height: 20px;
text-align: right;
border-right-color: navy;
}

Adjust left,width,position,top according to datagrid size and position.
http://www.mindfiresolutions.com/How-To-Fix-Datagrid-Pager-Position-Irrespective-of-Number-of-Records-Returned-147.php[^]
Cheers,
Eliza

QuestionHow To Fix Datagrid Pager Position Irrespective of Number of Records Returned Pin
elizas24-Feb-10 1:28
elizas24-Feb-10 1:28 
GeneralPaging Problem. Pin
Fenil Desai8-Dec-08 18:19
Fenil Desai8-Dec-08 18:19 
GeneralVb converted code for the same Pin
thas02227-Dec-07 3:37
thas02227-Dec-07 3:37 
AnswerRe: Vb converted code for the same Pin
thas02230-Dec-07 1:17
thas02230-Dec-07 1:17 
Questionhelp needed urgent *** Custom Paging with User Control Pin
kumaruday2-Aug-06 20:31
kumaruday2-Aug-06 20:31 
GeneralUserCotrol Paging Pin
v.venkannababu10-Jun-06 2:16
v.venkannababu10-Jun-06 2:16 
Generaldisplay next 10 records in asp Pin
Anonymous26-May-05 2:39
Anonymous26-May-05 2:39 
GeneralRe: display next 10 records in asp Pin
mehran.asg12-Feb-07 10:38
mehran.asg12-Feb-07 10:38 
GeneralTwo Control Pin
Leandro Souza26-Feb-05 4:36
Leandro Souza26-Feb-05 4:36 
QuestionIs there a way to do sorting as well as paging? Pin
Member 145018025-Nov-04 20:05
Member 145018025-Nov-04 20:05 
AnswerRe: Is there a way to do sorting as well as paging? Pin
linush27-Nov-04 8:55
linush27-Nov-04 8:55 
GeneralRe: Is there a way to do sorting as well as paging? Pin
codemonkeyman215-Mar-06 4:45
codemonkeyman215-Mar-06 4:45 
GeneralRe: Is there a way to do sorting as well as paging? Pin
linush15-Mar-06 5:07
linush15-Mar-06 5:07 
GeneralRe: Is there a way to do sorting as well as paging? Pin
codemonkeyman215-Mar-06 5:21
codemonkeyman215-Mar-06 5:21 
GeneralRe: Is there a way to do sorting as well as paging? Pin
linush15-Mar-06 5:47
linush15-Mar-06 5:47 
GeneralRe: Is there a way to do sorting as well as paging? Pin
codemonkeyman215-Mar-06 6:15
codemonkeyman215-Mar-06 6:15 
GeneralRe: Is there a way to do sorting as well as paging? Pin
linush15-Mar-06 13:26
linush15-Mar-06 13:26 
GeneralRe: Is there a way to do sorting as well as paging? Pin
codemonkeyman216-Mar-06 5:22
codemonkeyman216-Mar-06 5:22 
GeneralVB.net Version Pin
MSDevMan8-Jun-04 3:08
MSDevMan8-Jun-04 3:08 
GeneralRe: VB.net Version Pin
linush27-Nov-04 8:57
linush27-Nov-04 8:57 
GeneralRe: VB.net Version Pin
Anonymous31-May-05 2:53
Anonymous31-May-05 2:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.