From the MSDN page for the PagerTemplate
of the GridView
control (emphasis mine):
Typically, button controls are added to the pager template to perform the paging operations. The GridView control performs a paging operation when a button control with its CommandName property set to "Page" is clicked. The button's CommandArgument property determines the type of paging operation to perform.
- "Next": Navigates to the next page.
- "Prev": Navigates to the previous page.
- "First": Navigates to the first page.
- "Last": Navigates to the last page.
- Integer value: Navigates to the specified page number.
This stuff is pretty straightforward for the next/prev/first/last buttons because of their static nature.
<PagerTemplate>
<table>
<tr>
<td>
<asp:Button CommandName="Page" CommandArgument="First" Enabled="<%# Model.PageContext.HasPrevious %>" Text="First" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Prev" Enabled="<%# Model.PageContext.HasPrevious %>" Text="Previous" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Next" Enabled="<%# Model.PageContext.HasNext %>" Text="Next" runat="server" />
</td>
<td>
<asp:Button CommandName="Page" CommandArgument="Last" Enabled="<%# Model.PageContext.HasNext %>" Text="Last" runat="server" />
</td>
</tr>
</table>
</PagerTemplate>
On the other hand, the CommandArgument
for numeric buttons has to be dynamic and unique for each page that can be navigated to. I'm guessing I will need a for
-loop or a repeater control to get the right number of page links on the user's display.
Nothing I've tried seems to just work. My for-loop code doesn't even compile.
<% for (int pageIndex = 0; pageIndex < Model.PageContext.PageCount; pageIndex++) { %>
<asp:LinkButton CommandName="Page" CommandArgument="<%= pageIndex %>" Text="<%= pageIndex + 1 %>" runat="server"/>
<% } %>
My alternative approach uses a Repeater
control and does compile, but the Repeater
control itself handles the ItemCommand
for each button, preventing the "Page" ItemCommand
events from bubbling up to the GridView
.
<asp:Repeater ItemType="System.Int32" SelectMethod="GetPages" runat="server">
<ItemTemplate>
<asp:LinkButton CommandName="Page" CommandArgument="<%# Item %>" Text="<%# Item + 1 %>" runat="server" />
</ItemTemplate>
</asp:Repeater>
Each button raises the correct event, but the events never reach the GridView
because they are handled at a lower level by the Repeater
control. I have to attach an event handler that listens for RepeaterCommandEventArgs
and then set the new page index on the GridView
myself.
*Takes deep breath*
Can I add numeric page buttons without having to wire up events myself?
The result that I'm trying to achieve, based on the code above:

I figured out a way to get it done using the Repeater
control.
First, populate the repeater with link buttons for each page index (1-based) and attach an event handler for the OnItemCommand
event.
<asp:Repeater runat="server" ItemType="System.Int32" SelectMethod="GetPages" OnItemCommand="OnRepeaterCommand">
<ItemTemplate>
<asp:LinkButton CommandName="Page" CommandArgument="<%# Item %>" Text="<%# Item %>" runat="server" />
</ItemTemplate>
</asp:Repeater>
Pay special attention to how I'm binding my repeater to the collection of int
that is returned by GetPages
.
public IEnumerable<int> GetPages()
{
return Enumerable.Range(1, this.PageCount);
}
Finally, in the event handler, re-insert the CommandEventArgs
into the event pipeline using some reflection-fu.
protected void OnRepeaterCommand(object source, RepeaterCommandEventArgs e)
{
source.GetType()
.GetMethod("RaiseBubbleEvent", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(source, new[]
{
e.CommandSource,
new CommandEventArgs(e.CommandName, e.CommandArgument)
});
}
That's it. You don't have to do anything else. The GridView
will handle the ItemCommand
and set the page index to the new value.
I found an even simpler way, one that is framework 4.0 compatible
<asp:GridView ID="GridView_History" runat="server">
<PagerTemplate>
<asp:LinkButton ID="lnkPrev" runat="server" CommandName="Page" CommandArgument="Prev">Prev</asp:LinkButton>
<asp:Repeater ID="rptPagesHistory" OnItemDataBound="rptPagesHistory_ItemDataBound" runat="server" OnLoad="rptPagesHistory_Load">
<ItemTemplate>
<asp:LinkButton ID="lnkPageNumber" CommandName="Page" runat="server" OnClick="lnkPageNumberHistory_Click" />
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="lnkNext" runat="server" CommandName="Page" CommandArgument="Next">Next</asp:LinkButton>
</PagerTemplate>
</asp:GridView>
protected void rptPagesHistory_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
LinkButton lnkPageNumber = new LinkButton();
System.Int32 pageNumber = (System.Int32)e.Item.DataItem;
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
lnkPageNumber = (LinkButton)e.Item.FindControl("lnkPageNumber");
lnkPageNumber.Text = pageNumber;
lnkPageNumber.CommandArgument = pageNumber - 1;
}
}
protected void rptPagesHistory_Load(object sender, EventArgs e)
{
Repeater rpt = (Repeater)sender;
rpt.DataSource = Enumerable.Range(1, GridView_History.PageCount);
rpt.DataBind();
}
protected void lnkPageNumberHistory_Click(object sender, EventArgs e)
{
LinkButton btn = (LinkButton)sender;
GridView_History.PageIndex = btn.CommandArgument;
GridView_History.DataBind();
}
Here is the code, lifted right from the page(s).
<asp:GridView ID="grdUsage" PageSize="20" Width="100%" runat="server" AllowPaging="True" AllowSorting="False" CellPadding="4" ForeColor="#333333" GridLines="None" Font-Size="14px" Font-Bold="false" OnPageIndexChanging="grdUsage_PageIndexChanging" OnRowDataBound="grdUsage_RowDataBound" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="ID" HeaderStyle-HorizontalAlign="Center" ItemStyle-Width="100px" ItemStyle-Font-Size="12px">
<ItemTemplate>
<asp:Literal ID="lCampaignID" runat="server"></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderStyle-HorizontalAlign="Left">
<ItemTemplate>
<asp:HyperLink ID="lnkCampaign" runat="server" Target="_blank" Font-Size="12px"></asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" HorizontalAlign="Left" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#EFF3FB" />
<SelectedRowStyle BackColor="#D1DDF1" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
<AlternatingRowStyle BackColor="White" />
<PagerStyle HorizontalAlign="Center" BackColor="white" />
<PagerTemplate>
<ul class="pagination">
<li>
<asp:LinkButton ID="lnkPrev" runat="server" CommandName="Page" CommandArgument="Prev"><span>«</span></asp:LinkButton></li>
<asp:Repeater ID="rptPagesUsage" OnItemDataBound="rptPagesUsage_ItemDataBound" runat="server" OnLoad="rptPagesUsage_Load">
<ItemTemplate>
<asp:Literal ID="lListItem" runat="server"><li></asp:Literal><asp:LinkButton ID="lnkPageNumber" CommandName="Page" runat="server" OnClick="lnkPageNumberUsage_Click" /></li>
</ItemTemplate>
</asp:Repeater>
<li>
<asp:LinkButton ID="lnkNext" runat="server" CommandName="Page" CommandArgument="Next"> <span>»</span></asp:LinkButton></li>
</ul>
</PagerTemplate>
</asp:GridView>
Sub pGrid(sql as string) '
grdUsage.DataSource = G_GetDataTable(sql)
grdUsage.DataBind()
If grdUsage.Rows.Count > 0 Then
grdUsage.HeaderRow.Cells(1).Text = String.Format("Associated Campaigns for: <i>{0}</i>", txtEMailTitle.Text)
End If
End Sub
Protected Sub rptPagesUsage_Load(sender As Object, e As EventArgs)
Dim rpt As Repeater = DirectCast(sender, Repeater)
rpt.DataSource = Enumerable.Range(1, grdUsage.PageCount)
rpt.DataBind()
End Sub
Protected Sub rptPagesUsage_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
Dim lListItem As New Literal()
Dim lnkPageNumber As New LinkButton()
Dim pageNumber As System.Int32 = DirectCast(e.Item.DataItem, System.Int32)
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
lListItem = DirectCast(e.Item.FindControl("lListItem"), Literal)
lnkPageNumber = DirectCast(e.Item.FindControl("lnkPageNumber"), LinkButton)
lnkPageNumber.Text = pageNumber
lnkPageNumber.CommandArgument = pageNumber - 1
If e.Item.ItemIndex = grdUsage.PageIndex Then
lListItem.Text = "<li class=""active"">"
End If
End If
End Sub
Protected Sub grdUsage_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
hSelectedTab.Value = 5
If e.NewPageIndex >= 0 Then
grdUsage.PageIndex = e.NewPageIndex
pGrid(sql)
End If
End Sub
Protected Sub grdUsage_RowDataBound(sender As Object, e As GridViewRowEventArgs)
Dim drview As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim lnkCampaign As HyperLink = DirectCast(e.Row.FindControl("lnkCampaign"), HyperLink)
Dim lCampaignID As Literal = DirectCast(e.Row.FindControl("lCampaignID"), Literal)
lnkCampaign.Text = drview("CampaignTitle").ToString()
lCampaignID.Text = drview("EmailCampaignID").ToString()
lnkCampaign.NavigateUrl = String.Format("/Admin/WF_Admin_Campaign_Email_Detail.aspx?ID={0}", drview("EmailCampaignID").ToString())
End If
End Sub
Protected Sub lnkPageNumberUsage_Click(sender As Object, e As EventArgs)
Dim btn As LinkButton = DirectCast(sender, LinkButton)
grdUsage.PageIndex = btn.CommandArgument
pGrid(sql)
End Sub
I also created an extension for the grid that is also in use.
Public Module ControlUtilities
<Extension()>
Public Sub CustomPager(ByRef grd As GridView)
Dim cp As New clsCustomPager(grd)
End Sub
Public Class clsCustomPager
Public _grd As GridView
Public Property rpt() As GridView
Get
Return _grd
End Get
Set(value As GridView)
_grd = value
End Set
End Property
Public Sub New(ActiveGridView As GridView)
_grd = ActiveGridView
Me.CustomPages()
End Sub
''' <summary>
''' create the objects needed for a bootstrap driven navigation for a gridview
''' </summary>
Sub CustomPages()
If Not _grd Is Nothing And Not _grd.BottomPagerRow Is Nothing Then
'hook event handler to grid
AddHandler _grd.PageIndexChanging, AddressOf Me.Grid_PageIndexChanging
'declare variables
Dim pagerRow As GridViewRow = _grd.BottomPagerRow
Dim lnkPrev As LinkButton = New LinkButton()
Dim lnkNext As LinkButton = New LinkButton()
'set up previous link
lnkPrev.CommandArgument = "Prev"
lnkPrev.CommandName = "Page"
lnkPrev.Text = "<span>«</span>"
'set up next link
lnkNext.CommandArgument = "Next"
lnkNext.CommandName = "Page"
lnkNext.Text = "<span>»</span>"
'create html unordered list
pagerRow.Cells(0).Controls.Add(New LiteralControl("<ul class=""pagination"">"))
'add previous link
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
pagerRow.Cells(0).Controls.Add(lnkPrev)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
Dim pageNumber As Integer
For Each pageNumber In Enumerable.Range(1, _grd.PageCount)
'create page link object
Dim lnkPage As LinkButton = New LinkButton()
lnkPage.CommandName = "Page"
lnkPage.Text = pageNumber
lnkPage.CommandArgument = (pageNumber - 1)
AddHandler lnkPage.Click, AddressOf Me.lnkPageNumber_Click 'event handler
'set css class if selected or not
If (pageNumber - 1) = _grd.PageIndex Then
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li class=""active"">"))
Else
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
End If
'add lnk and close html listitem
pagerRow.Cells(0).Controls.Add(lnkPage)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
Next
'add next link
pagerRow.Cells(0).Controls.Add(New LiteralControl("<li>"))
pagerRow.Cells(0).Controls.Add(lnkNext)
pagerRow.Cells(0).Controls.Add(New LiteralControl("</li>"))
'close up unordered list
pagerRow.Cells(0).Controls.Add(New LiteralControl("</ul>"))
End If
End Sub
''' <summary>
''' event handler for previous/next buttons
''' </summary>
Protected Sub Grid_PageIndexChanging(sender As Object, e As GridViewPageEventArgs)
If e.NewPageIndex >= 0 Then
_grd.PageIndex = e.NewPageIndex
_grd.DataBind()
Me.CustomPages()
End If
End Sub
''' <summary>
''' event handler for numeric link buttons
''' </summary>
Protected Sub lnkPageNumber_Click(sender As Object, e As EventArgs)
Dim btn As LinkButton = DirectCast(sender, LinkButton)
_grd.PageIndex = btn.CommandArgument
_grd.DataBind()
Me.CustomPages()
End Sub
End Class
End Module
来源:https://stackoverflow.com/questions/26385838/dynamically-generate-page-linkbuttons-for-the-pagertemplate-of-a-gridview