自定义模板分页控件
一个在实现服务器端分页时特别有用的分页控件。
引言
对大型结果集进行服务器端分页是Web开发人员的一项常见(且重要)任务。将其与数据控件结合使用时,需要提供某种形式的分页UI。简单的前进和后退按钮有时就足够了,但当预期页数较多时,它们并不能真正提供引人注目的界面。在这种情况下设置其他形式的分页可能会非常耗时,无论您是使用PagedDataSource
类还是创建一些自定义方法。而且,我经常发现特定站点的设计限制会要求对我的分页类进行费力的重写。
CodeProject上还有其他一些分页控件可以查看,这里和这里。我编写的分页控件(主要)不同之处在于它是模板化的,允许轻松实现任何形式的分页UI。如果您希望使用任何类型的按钮,它会响应ItemCommand
事件,或者(对于更注重SEO的人来说)与查询字符串链接同样适用。
附件的zip文件包含编译后的DLL、完整的控件源代码以及WebForm上的几个示例实现。
背景
这是我开发的第一个模板化控件。我发现在尝试这样做时有很多东西需要“发现”。我不会在这里详细介绍所有细节,但以下资源被证明很有用
- Reflector。我(经常)使用它,在这种情况下,是为了彻底研究
Repeater
控件。 - Scott Mitchell 在 MSDN 上的几篇优秀文章:模板化控件 和 数据绑定模板化控件。
- CodeProject上的一篇好文章,介绍了编写自定义控件的一些挫折和解决方案。
有许多关于服务器端分页的资源可用,具体取决于您使用的数据库类型。在 Oracle 和 SQL Server 2005 中非常简单。本文很好地介绍了 SQL Server 2000 可用的方法。
使用 TemplatedPager
尝试该控件最简单的方法是右键单击您的 VS2005 工具箱,选择“选择项”,浏览到您解压缩附件文件的位置,然后选择 TemplatedPager.dll。然后,将该控件的实例从您的工具箱拖到您的 WebForm 上。
模板
有8个模板可用。所有模板都可以访问容器页码属性。
<%#Container.PageNumber%>
和页面计数属性。
<%#Container.PageCount%>
注意,在分隔符模板中,这些属性不会返回任何内容,因为此模板未绑定数据。
HeaderTemplate
将始终通过 Container.PageNumber
返回当前页。
<HeaderTemplate>
Page <%#Container.PageNumber%> of <%#Container.PageCount%>:
</HeaderTemplate>
FirstPageTemplate
和 LastPageTemplate
允许您指定任何“转到首页/末页”元素的外观和行为。此模板中的Container.PageNumber
在FirstPage
情况下始终为1,在LastPage
情况下为最后一页页码。如果此模板未包含并且控件的ShowFirst
/ShowLast
属性设置为true,则此信息将通过标准PageTemplate
呈现。
PreviousPageTemplate
和 NextPageTemplate
非常明显。然而,与首页和末页模板不同,如果它们对应的模板在控件中不存在,则它们不会通过 PageTemplate
呈现。请注意,这些模板的 ShowNext
和 ShowPrevious
属性应设置为 true 才能呈现。
CurrentPageTemplate
允许当前选定的页面以不同于其他页面的样式显示,其他页面将使用PageTemplate
。
<CurrentPageTemplate>
<strong><%#Container.PageNumber%></strong>
</CurrentPageTemplate>
<PageTemplate>
<asp:LinkButton ID="lP" CommandName="Page"
CommandArgument="<%#Container.PageNumber%>"
runat="server"><%#Container.PageNumber%></asp:LinkButton>
</PageTemplate>
最后,SeparatorTemplate
允许您指定应在每个页码之间呈现的 HTML。请注意,它仅应用于 CurrentPageTemplate
和 PageTemplate
实例之间。
属性
这些可以在设计时和/或运行时设置
MaxPageNumbers
要显示的页码数量。PageCount
您可以设置此属性,或PagedItemCount
属性。如果您设置此属性,无论PagedItemCount
的值是什么,都将使用此属性而不是PagedItemCount
。PagedItemCount
要让页面计数为您计算,请使用要分页的总项目数设置此属性。此外,请务必设置PageSize
属性以获取准确的页面计数。计算公式为CType(Math.Ceiling(PagedItemCount / PageSize), Integer)
。PageNumber
当前页码。不能小于1。PageSize
每页项目数。ShowFirst
,ShowLast
,ShowPrevious
,ShowNext
布尔值,指示是否绑定关联的模板。
事件
ItemCommand
事件允许您将按钮控件放入模板中并响应引发的事件。例如
Protected Sub TemplatedPager1_ItemCommand(ByVal sender As Object, _
ByVal e As Bxi.Web.UI.WebControls.PagerItemCommandEventArgs) _
Handles TemplatedPager1.ItemCommand
If e.CommandName = "Page" Then
TemplatedPager1.PageNumber = e.CommandArgument
End If
End Sub
注意:无需在此控件上调用“DataBind
”。这是在控件内部由一个requiresBind
标志处理的,该标志在控件属性更改时设置。
关注点
在开发(模板化)控件时,会遇到一些“障碍”。这里有一些以及我发现的解决方案
- 我最初是从
WebControl
继承的。它对于此控件有很多不必要的继承属性,所以我将其更改为从Control
继承。现在,当我尝试在控件中添加模板时,我看到的是服务器控件的完整列表,而不是只看到我的模板。通过添加属性ParseChildren(True)
和PersistChildren(False)
解决了这个问题。关于为什么这是必要的,有一篇信息丰富的博客,这里。 - 从
Control
继承也导致无法再访问容器属性(例如,Container.PageNumber
)。大量的尝试和错误导致发现需要在将模板类(在我的情况下是PagerItem
)添加到Controls
集合后调用其DataBind
方法,有趣的是,在从WebControl
继承时这是不必要的。 - 这很傻,但我喜欢为控件关联一个漂亮的图标,使用
ToolboxBitmap
属性(为了节省你几分钟时间,它在System.Drawing
中)。这实际上比编写大部分控件逻辑花费的时间更长。Bob Powell 在这里有一篇好文章,虽然完全不起作用,但让我找到了正确的方向。如果你遵循所有这些说明,但仍然无法显示你的图标,请在 Reflector 中打开你的 .dll,查看资源,然后找到你的 .bmp 图像(你应该将其构建操作设置为“嵌入式资源”)。如果它的名称不包含根命名空间(如果有)、命名空间以及它在 VS 中可能存在的任何子目录,请将 .bmp 文件重命名为包含所有这些。在我的例子中,我将文件名更改为 Bxi.Web.UI.WebControls.Resources.TemplatedPager.bmp,然后成功了。 - 请注意您的根命名空间。我更喜欢不使用它,并在类中显式地写出完整的命名空间。很容易忘记它,然后导致与您的控件设计器或您的程序集
TagPrefix
的关联等问题。
改进
我很乐意听取任何反馈和改进建议,特别是如果您对模板化控件开发有任何建议/评论/想法。
历史
- 版本 1:2007 年 8 月 28 日。