Repeater with Paging: Performing Postback on a Custom Control






2.71/5 (4 votes)
Repeater with paging: a custom ASP.NET control.
Introduction
With the out-of-the-box ASP.NET DataGrid
or GridView
, it's very easy to control data with paging. However, the weakness is you have to bind all data in order to make the paging to work. It's not practical. Let's say you have 1,000,000 number of data rows and you want to display only 25 per page, you will not want to bind the whole 1,000,000 data rows just for making the paging to work.
This control that I wrote inherits from Repeater
, and I added a Literal
control for the paging. This control also implements IPostBackEventHandler
, which allows you to perform postback to the server (used by the Literal
for the paging). This control allows you to bind only the data that you want to display to the user, but also makes the paging to work.
Background
This article is only for intermediate-advanced ASP.NET developers who have had experience in creating custom controls. The files attached are .vb files which you need to add to your own project. I will not explain how to create a Class Library project in Visual Studio, etc.
This control will use a custom EventArgs
and delegates and events. If you're not familiar with these, you may get confused.
Using the Code
From the file attachment, RepeaterWithPaging.vb.
- Add a reference to
System.Web
. - Add the
Imports
declarations. - Inherit from
Repeater
and implementIPostBackEventHandler
to allow postback. - Create the required class variables and properties.
- Implement the required method from
IPostBackEventHandler
. This method is called when the postback is triggered by the paging. I'll explain this later. - Create a delegate for handling the postback event by the paging literal.
- Create an event based on that delegate.
- The
PagingLiteralEventArgs
class is defined in the file PagingLiteralEventArgs.vb. This file inherits from theEventArgs
class, and it has a public propertyCurrentPage
. UsingEventArgs
, you can pass arguments. You can add as many arguments as you want, but for the paging literal control to work, we only need theCurrentPage
property which we use to get the current page number viewed by the user. - Back to RepeaterWithPaging.vb. We now need to initialize the
Literal
for paging. Let's override theOnInit
method from the base class, and also, when the page is not posting back, we set the current page number to 1. - Populate the paging literal. I want to stress out this method:
- Within
RaisePostBackEvent()
, trigger thePagingClicked
event we declares previously. It means that when the text is clicked on the paging literal, the PagingClicked event is fired. We then pass in the page number argument that is passed through theeventArgument
variable. - Render both the
Repeater
and theLiteral
.
Imports System.Collections.Generic
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Public Class RepeaterWithPaging _
Inherits Repeater _
Implements IPostBackEventHandler
#Region "Class Variables"
Private litPaging As Literal 'THE LITERAL CONTROL FOR PAGING
Private intNumberOfData As Integer
Private intNumberPerPage As Integer
Private intCurrentPageNumber As Integer
Private strPagingCssClass As String
Public Event PagingClicked As PagingLiteralEventHandler
#End Region
#Region "Public Properties"
'Used by the paging literal to display the page number from 1 to x
'depending on the number of data specified here.
Public Property NumberOfData() As Integer
Get
Return intNumberOfData
End Get
Set(ByVal Value As Integer)
intNumberOfData = Value
End Set
End Property
'The number of data displayed per page, used by paging literal as well.
Public Property NumberPerPage() As Integer
Get
Return intNumberPerPage
End Get
Set(ByVal Value As Integer)
intNumberPerPage = Value
End Set
End Property
'Current page viewed.
Public Property CurrentPageNumber() As Integer
Get
Return Me.intCurrentPageNumber
End Get
Set(ByVal value As Integer)
Me.intCurrentPageNumber = value
End Set
End Property
'The CSS class for the paging literal
Public Property PagingCssClass() As String
Get
Return Me.strPagingCssClass
End Get
Set(ByVal value As String)
Me.strPagingCssClass = value
End Set
End Property
#End Region
Public Sub RaisePostBackEvent(ByVal eventArgument As String) _
Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
End Sub
Public Delegate Sub PagingLiteralEventHandler(ByVal sender As Object, _
ByVal ev As PagingLiteralEventArgs)
Public Event PagingClicked As PagingLiteralEventHandler
Public Class PagingLiteralEventArgs
Inherits EventArgs
#Region "Class Variables"
Private intCurrentPage As Integer
#End Region
#Region "Public Properties"
Public Property CurrentPage() As Integer
Get
Return intCurrentPage
End Get
Set(ByVal Value As Integer)
intCurrentPage = Value
End Set
End Property
#End Region
End Class
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
litPaging = New Literal
Me.Controls.Add(litPaging) 'Add to control collection
If Not Me.Page.IsPostBack Then
Me.intCurrentPageNumber = 1
End If
End Sub
Me.Page.ClientScript.GetPostBackEventReference(Me, i)
This method is the one that triggers the postback! You can add this method as a JavaScript call, and if you View Source in Internet Explorer or Firefox, you can see that it renders as _doPostBack()
. This method passes two input parameters: the calling control and the argument. I pass Me
as the control and the page number (denoted by "i
" - see the method below) to pass the clicked page number as the argument.
This will then be captured by this method implemented from the interface explained earlier:
RaisePostBackEvent(ByVal eventArgument As String)
The eventArgument
variable will contain the argument passed.
Private Sub PopulatePaging()
'Number of pages is obtained by dividing number of data with number per page
Dim intNoOfPages As Integer = Me.NumberOfData / Me.NumberPerPage
'If there is still extra data
'e.g Number of data is 303 and number per page is 100
'there are still 3 items left after page 3, so add page by 1.
If Me.NumberOfData Mod Me.NumberPerPage > 0 Then
intNoOfPages += 1
End If
'Display paging from 1 to number of pages
For i As Integer = 1 To intNoOfPages
'If user navigates to the current page, make it bold.
If i = Me.intCurrentPageNumber Then
Me.litPaging.Text &= "<a class=""" & _
Me.PagingCssClass & """ href=""#"" onclick=""" & _
Me.Page.ClientScript.GetPostBackEventReference(Me, i) & _
"""><b>" & i & "</b></a> | "
Else
'Make it normal
Me.litPaging.Text &= "<a class=""" & Me.PagingCssClass & _
""" href=""#"" onclick=""" & _
Me.Page.ClientScript.GetPostBackEventReference(Me, i) & """>" & _
i & "</a> | "
End If
Next
End Sub
Public Sub RaisePostBackEvent(ByVal eventArgument As String) _
Implements System.Web.UI.IPostBackEventHandler.RaisePostBackEvent
'This is the power of custom EventArgs, you can pass it as an argument
Dim objEventArgs As New PagingLiteralEventArgs
objEventArgs.CurrentPage = CInt(eventArgument)
Me.intCurrentPageNumber = eventArgument
'Raise the event with passing the custom PagingLiteralEventArgs
RaiseEvent PagingClicked(Me, objEventArgs)
End Sub
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
MyBase.Render(writer)
writer.Write("<p/>")
Me.PopulatePaging()
Me.litPaging.RenderControl(writer)
End Sub
That's it! Now, let's go to the front end ASPX page.
Front-End
- Register your custom control.
- Declare your custom repeater as a normal repeater, but note the custom properties and the event we created earlier. When you create a new event based on a custom delegate (in this case,
PagingClicked
), Visual Studio automatically adds the "On" word in front of it! Pretty good! When you view the properties of theRepeater
from the ASPX, you can see theOnPagingClicked
event is there! - On the code-behind, let's capture the
Paging_Clicked
event. - Bind the test data and test the paging.
<%@ Register TagPrefix="CRE" Namespace="ContentReadyEnterprise.Web.Controls"
Assembly="ContentReadyEnterprise.Web.Controls" %>
<CRE:RepeaterWithPaging ID="rptTest" runat="server"
OnPagingClicked="Paging_Clicked"
NumberOfData="100" NumberPerPage="10">
<ItemTemplate>
<%#Container.DataItem%>
<br />
</ItemTemplate>
</CRE:RepeaterWithPaging>
Protected Sub Paging_Clicked(ByVal sender As Object, ByVal ev As PagingLiteralEventArgs)
Response.Write("I click page number: " & ev.CurrentPage.ToString())
End Sub
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Me.GetTestData()
End If
End Sub
'Capture paging event
Protected Sub Paging_Clicked(ByVal sender As Object, _
ByVal ev As PagingLiteralEventArgs)
Me.GetTestData()
End Sub
'You can write your own method here.
Private Sub GetTestData()
Dim alistTest As New List(Of String)
Dim intStartNumber As Integer = _
rptTest.CurrentPageNumber * rptTest.NumberPerPage
If rptTest.CurrentPageNumber = 1 Then
intStartNumber = 1
End If
Dim intEndNumber As Integer = intStartNumber + rptTest.NumberPerPage
For i As Integer = intStartNumber To intEndNumber
alistTest.Add(i)
Next
rptTest.DataSource = alistTest
rptTest.DataBind()
End Sub
That's it guys!
Points of Interest
It's very interesting to see how easy it is to make a control that can do postback.