带分页的 Repeater: 在自定义控件上执行 Postback






2.71/5 (4投票s)
带分页的 Repeater:一个自定义 ASP.NET 控件。
引言
使用现成的 ASP.NET DataGrid
或 GridView
,可以非常方便地实现数据分页。然而,它们的缺点是您必须绑定 **所有** 数据才能使分页生效。这并不实用。假设您有 1,000,000 条数据,并且只想每页显示 25 条,您肯定不希望仅仅为了实现分页而绑定全部 1,000,000 条数据。
我编写的这个控件继承自 Repeater
,并且我添加了一个 Literal
控件用于分页。该控件还实现了 IPostBackEventHandler
接口,这允许您执行服务器回发(Literal
用于分页时会用到)。该控件允许您只绑定想要显示给用户的数据,同时也能实现分页功能。
背景
本文档仅面向有自定义控件创建经验的中高级 ASP.NET 开发人员。提供的文件是 .vb 文件,您需要将它们添加到自己的项目中。我 **不会** 解释如何在 Visual Studio 中创建类库项目等内容。
该控件将使用自定义的 EventArgs
、委托和事件。如果您不熟悉这些概念,可能会感到困惑。
Using the Code
从附件文件 RepeaterWithPaging.vb 中。
- 添加对
System.Web
的引用。 - 添加
Imports
声明。 - 继承自
Repeater
并实现IPostBackEventHandler
以允许回发。 - 创建所需的类变量和属性。
- 实现
IPostBackEventHandler
所需的方法。当分页触发回发时,会调用此方法。我稍后会解释这一点。 - 创建一个委托,用于处理分页 Literal 触发的回发事件。
- 基于该委托创建一个事件。
PagingLiteralEventArgs
类定义在文件 PagingLiteralEventArgs.vb 中。该文件继承自EventArgs
类,并具有一个公共属性CurrentPage
。使用EventArgs
,您可以传递参数。您可以添加任意数量的参数,但对于分页 Literal 控件正常工作,我们只需要CurrentPage
属性,用于获取用户正在查看的当前页码。- 回到 RepeaterWithPaging.vb。现在我们需要初始化用于分页的
Literal
控件。我们重写基类的OnInit
方法,并且当页面不是回发时,我们将当前页码设置为 1。 - 填充分页 Literal。我想要强调这个方法
- 在
RaisePostBackEvent()
中,触发我们之前声明的PagingClicked
事件。这意味着当分页 Literal 上的文本被点击时,PagingClicked
事件就会被触发。然后我们将通过eventArgument
变量传递过来的页码参数传入。 - 渲染
Repeater
和Literal
。
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)
这个方法是触发回发的关键!您可以将此方法添加为 JavaScript 调用,如果您在 Internet Explorer 或 Firefox 中查看源代码,可以看到它会渲染为 _doPostBack()
。此方法传递两个输入参数:调用控件和参数。我将 Me
作为控件,并将页码(由“i
”表示 - 请参见下面的方法)作为参数传递点击的页码。
这将被前面解释的接口实现的方法捕获
RaisePostBackEvent(ByVal eventArgument As String)
eventArgument
变量将包含传递过来的参数。
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
就是这样!现在,让我们转到前端 ASPX 页面。
前端
- 注册您的自定义控件。
- 像普通 Repeater 一样声明您的自定义 Repeater,但请注意我们之前创建的自定义属性和事件。当您基于自定义委托(在本例中为
PagingClicked
)创建新事件时,Visual Studio 会自动在其前面添加“On”前缀!这很棒!当您在 ASPX 中查看Repeater
的属性时,可以看到OnPagingClicked
事件就在那里! - 在代码隐藏文件中,捕获
Paging_Clicked
事件。 - 绑定测试数据并测试分页。
<%@ 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
各位,就这样了!
关注点
看到实现一个能够回发的控件如此之容易,真是太有趣了。