在搜索结果中实现可点击的页码

发布于 2024-07-16 00:22:12 字数 1636 浏览 8 评论 0原文

经典场景:接受用户输入,获取搜索结果并将其在页面中显示给用户。 然后,我需要显示“第一个”、“下一个”、“上一个”等按钮,并将用户当前页面维护在视图状态中。 一切都很好,工作正常。

然后我需要实现可点击的页码,即。 1-2-3-4-5-6 等。

渲染它们很简单。 我在运行时生成一个链接按钮控件,添加带有页码的命令参数并向其添加一个处理程序,以便处理单击。 然后我将其添加到占位符中,它会按预期显示。

但是……如果我还没有剃光头,我就会拔掉头发,让事件每次都按预期触发。

我应该如何执行此操作,以便我的事件始终连接并能够在调用分页链接按钮时触发?

下面是代码的重要部分,一些伪代码使其(希望)更容易理解,我正在做什么。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  If Not Page.IsPostBack Then
     Search()
  End If
End Sub

Sub Search
    'Misc databinding stuff, searches and displays results for the page specified in Me.CurrentPage
    RenderPagingControls()
End Sub

Sub RenderPagingControls
   'loop throug pagenumbers, Build a linkbutton control, add it to a placeholder
    AddHandler lbn.Click, AddressOf lbnNumber_Click
    lblPageNumbers.Controls.Add(lbn)
    ...

End Sub

Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
    Dim b As LinkButton = CType(sender, LinkButton)
    Me.CurrentPage = CInt(b.CommandArgument)
    Search()
End Sub

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.ViewState("CurrentPage")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("CurrentPage") = value
    End Set
End Property

Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
    Dim b As LinkButton = CType(sender, LinkButton)
    Me.CurrentPage = CInt(b.CommandArgument)
    Search()
End Sub

Classic scenario: Take user input, get a search-result and display it in pages to the user. I then need to display buttons for First, Next, Previous etc, and I maintain the users current page in viewstate. All is good, works fine.

Then I need to implement clickable page numbers, ie. 1-2-3-4-5-6 etc.

Rendering them is simple. I generate a linkbutton control at runtime, add commandargument with the page number and add a handler to it, so click are to be handled. Then I add it to a placeholder, and it is displayed as expected.

But then... If I did not already have a shaved head, I would be pulling out my hair getting the events to fire as expected every time.

How should I do this, so my events are always wired up and able to fire when the paging-linkbuttons are called?

Below is the important parts of the code, some pseudo to make it (hopefully) easier to understand, what I am doing.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  If Not Page.IsPostBack Then
     Search()
  End If
End Sub

Sub Search
    'Misc databinding stuff, searches and displays results for the page specified in Me.CurrentPage
    RenderPagingControls()
End Sub

Sub RenderPagingControls
   'loop throug pagenumbers, Build a linkbutton control, add it to a placeholder
    AddHandler lbn.Click, AddressOf lbnNumber_Click
    lblPageNumbers.Controls.Add(lbn)
    ...

End Sub

Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
    Dim b As LinkButton = CType(sender, LinkButton)
    Me.CurrentPage = CInt(b.CommandArgument)
    Search()
End Sub

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.ViewState("CurrentPage")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("CurrentPage") = value
    End Set
End Property

Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
    Dim b As LinkButton = CType(sender, LinkButton)
    Me.CurrentPage = CInt(b.CommandArgument)
    Search()
End Sub

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风吹过旳痕迹 2024-07-23 00:22:12

我将建议不要使用 LinkBut​​ton,并推荐使用 Hyperlinks / QueryString 参数。 出于以下几个原因:

  1. 如果没有链接按钮的视图状态开销,您的页面将会更加高效。
  2. 如果这些是面向公众的页面,如果可以通过超链接访问它们(并通过搜索引擎建立索引),您将获得更好的所有页面索引。
  3. 您会发现它们更容易实施。 没有事件管理等。

您可以将 CurrentPage 方法重新定义为(希望这是正确的,我在 C# 方面比 vb.net 更好):

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.Request.QueryString("page")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
End Property

然后只需为每个页面添加超链接。

<a href='mypage.aspx?page=1'>1</a> - <a href='mypage.aspx?page=2'>2</a>
etc...

替代方案:如果您想使用 LinkBut​​ton,您可能需要考虑将单个 LinkBut​​ton 放入转发器中。 那么您唯一需要担心的事件是 OnItemCommand 事件。 然后就没有动态控件或事件。 像这样的事情:

<asp:Repeater ID="rptPages" runat="server" OnItemCommand='doPaging'>
  <ItemTemplate>
    <asp:LinkButton ID="LinkButton1" runat="server" Text='<%# (Container.DataItem).ToString()  %>'
    CommandArgument='<%# (Container.DataItem).ToString() %>' />
  </ItemTemplate>
  <SeparatorTemplate>-</SeparatorTemplate>
</asp:Repeater>

将此控件绑定到连续整数的数组(或列表)(有多少页)。 然后在 doPaging 函数(我这样称呼它)中,检查 RepeaterCommandEventArgs.CommandArgument 以获取页码。

I'm going to recommend against a LinkButton and recommend Hyperlinks / QueryString parameters instead. For several reasons:

  1. Your page will be much more efficient without the viewstate overhead of a link button.
  2. If these are public facing pages, you'll get better indexing of all the pages if they can be accessed via hyperlinks (and indexed via search engines).
  3. You'll find them much easier to implement. No event management, etc.

You would redefine your CurrentPage method as (hopefully this is correct, I'm better at C# than vb.net):

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.Request.QueryString("page")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
End Property

Then just add hyperlinks for each page.

<a href='mypage.aspx?page=1'>1</a> - <a href='mypage.aspx?page=2'>2</a>
etc...

Alternative: If you want to use the LinkButton, you might want to consider putting a single LinkButton in a repeater. Then the only event you have to worry about is the OnItemCommand event. Then no dynamic controls or events. Something like this:

<asp:Repeater ID="rptPages" runat="server" OnItemCommand='doPaging'>
  <ItemTemplate>
    <asp:LinkButton ID="LinkButton1" runat="server" Text='<%# (Container.DataItem).ToString()  %>'
    CommandArgument='<%# (Container.DataItem).ToString() %>' />
  </ItemTemplate>
  <SeparatorTemplate>-</SeparatorTemplate>
</asp:Repeater>

Bind this control to an array (or list) of consecutive Integers (as many are there are pages). Then in your doPaging function (as I call it), check RepeaterCommandEventArgs.CommandArgument to get the page number.

怎樣才叫好 2024-07-23 00:22:12

谢谢你们的回答,伙计们。 我首先尝试了 Austins,但我一定错过了一些东西,因为我一直得到链接按钮的相同行为,仅每秒工作一次......所以我放弃了,并看到了 Keltex 中继器的替代解决方案! 它既出色又简单,而且我们不必担心任何页面生命周期的废话。

它确实有效! ;)

如果有人将来需要类似的东西,这里是幕后的相关代码:

Sub Search()
    ...
    RenderPagingControls()
End Sub

Sub RenderPagingControls()
    Dim pages As New ArrayList
    For i As Integer = 1 To Me.PageCount
        pages.Add(i)
    Next

    repPageNumbersTop.DataSource = pages
    repPageNumbersTop.DataBind()

    repPageNumbersBottom.DataSource = pages
    repPageNumbersBottom.DataBind()

End Sub

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.ViewState("CurrentPage")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("CurrentPage") = value
    End Set
End Property

Public Property PageCount() As Integer
    Get
        Dim o As Object = Me.ViewState("PageCount")
        If o Is Nothing Then
            Return 0
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("PageCount") = value
    End Set
End Property


Protected Sub repPageNumbersTop_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles repPageNumbersTop.ItemCommand, repPageNumbersBottom.ItemCommand
    Me.CurrentPage = CType(e.CommandArgument, Integer)
    Search()
End Sub

Private Sub repPageNumbersTop_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repPageNumbersTop.ItemDataBound, repPageNumbersBottom.ItemDataBound
    If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
        Dim lbn As LinkButton = CType(e.Item.FindControl("lbnPageNumber"), LinkButton)
        If lbn.CommandArgument = Me.CurrentPage.ToString Then
            lbn.Enabled = False
        End If
    End If
End Sub

Thanks for the answers, guys. I tried out Austins first, but I must be missing something, because I keep getting the same behavior of link buttons only working every second time... So I gave up on that, and saw the alternative solution with the repeater by Keltex! It is as brilliant as it is simple, and we don't have to worry about any page life-cycle bullshit.

It just really works! ;)

If somebody should need something similar in the future, here is the relevant code behind the scenes:

Sub Search()
    ...
    RenderPagingControls()
End Sub

Sub RenderPagingControls()
    Dim pages As New ArrayList
    For i As Integer = 1 To Me.PageCount
        pages.Add(i)
    Next

    repPageNumbersTop.DataSource = pages
    repPageNumbersTop.DataBind()

    repPageNumbersBottom.DataSource = pages
    repPageNumbersBottom.DataBind()

End Sub

Public Property CurrentPage() As Integer
    Get
        Dim o As Object = Me.ViewState("CurrentPage")
        If o Is Nothing Then
            Return 1
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("CurrentPage") = value
    End Set
End Property

Public Property PageCount() As Integer
    Get
        Dim o As Object = Me.ViewState("PageCount")
        If o Is Nothing Then
            Return 0
        Else
            Return CType(o, Integer)
        End If
    End Get
    Set(ByVal value As Integer)
        Me.ViewState("PageCount") = value
    End Set
End Property


Protected Sub repPageNumbersTop_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles repPageNumbersTop.ItemCommand, repPageNumbersBottom.ItemCommand
    Me.CurrentPage = CType(e.CommandArgument, Integer)
    Search()
End Sub

Private Sub repPageNumbersTop_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repPageNumbersTop.ItemDataBound, repPageNumbersBottom.ItemDataBound
    If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
        Dim lbn As LinkButton = CType(e.Item.FindControl("lbnPageNumber"), LinkButton)
        If lbn.CommandArgument = Me.CurrentPage.ToString Then
            lbn.Enabled = False
        End If
    End If
End Sub
别忘他 2024-07-23 00:22:12

此代码有效(抱歉,它是用 C# 编写的):

protected void SearchButton_Click(object sender, EventArgs e)
{
    //clear the collection!
    pnlPageNumber.Controls.Clear();

    //simulate search
    System.Random rnd = new Random();

    //create page buttons
    for (int i = 0; i < rnd.Next(3, 15); i++)
    {
        LinkButton lb = new LinkButton();
        pnlPageNumber.Controls.Add(lb);
        lb.ID = "btn" + i;
        lb.Text = i.ToString();
        lb.CommandArgument = i.ToString();
        lb.Command += new CommandEventHandler(linkbutton_Command);

        //optional literal
        pnlPageNumber.Controls.Add(new LiteralControl(" "));
    }

    ViewState["control#"] = Panel1.Controls.Count;
}

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
    {
        //Recreate link buttons
        //This is necessary to ensure proper event binding

        int count = 0;

        if (ViewState["control#"] != null)
            count = (int)ViewState["control#"];

        for (int i = 0; i < count; i++)
        {
            LinkButton lb = new LinkButton();
            pnlPageNumber.Controls.Add(lb);
            lb.ID = "btn" + i; //make sure IDs are the same here and on Search
            lb.Command += new CommandEventHandler(linkbutton_Command);

            //this is not necessary, but if you do, make sure its in both places
            pnlPageNumber.Controls.Add(new LiteralControl(" "));
        }
    }
}

void linkbutton_Command(object sender, CommandEventArgs e)
{
    Response.Write(e.CommandArgument.ToString() + " CLICK<br />");
}

This code works (sorry it's in C#):

protected void SearchButton_Click(object sender, EventArgs e)
{
    //clear the collection!
    pnlPageNumber.Controls.Clear();

    //simulate search
    System.Random rnd = new Random();

    //create page buttons
    for (int i = 0; i < rnd.Next(3, 15); i++)
    {
        LinkButton lb = new LinkButton();
        pnlPageNumber.Controls.Add(lb);
        lb.ID = "btn" + i;
        lb.Text = i.ToString();
        lb.CommandArgument = i.ToString();
        lb.Command += new CommandEventHandler(linkbutton_Command);

        //optional literal
        pnlPageNumber.Controls.Add(new LiteralControl(" "));
    }

    ViewState["control#"] = Panel1.Controls.Count;
}

protected void Page_Load(object sender, EventArgs e)
{
    if (IsPostBack)
    {
        //Recreate link buttons
        //This is necessary to ensure proper event binding

        int count = 0;

        if (ViewState["control#"] != null)
            count = (int)ViewState["control#"];

        for (int i = 0; i < count; i++)
        {
            LinkButton lb = new LinkButton();
            pnlPageNumber.Controls.Add(lb);
            lb.ID = "btn" + i; //make sure IDs are the same here and on Search
            lb.Command += new CommandEventHandler(linkbutton_Command);

            //this is not necessary, but if you do, make sure its in both places
            pnlPageNumber.Controls.Add(new LiteralControl(" "));
        }
    }
}

void linkbutton_Command(object sender, CommandEventArgs e)
{
    Response.Write(e.CommandArgument.ToString() + " CLICK<br />");
}
夜巴黎 2024-07-23 00:22:12

您可以使用 DataPager 控件 - 唯一的限制是您必须将其与 ListView 控件一起使用,但您应该能够相当轻松地使用 ListView 控件来表示数据,因为它非常灵活。 您可以将 ListView 控件的 DataSource 设置为数据结果的结果,无论是 DataSet、Collection、Array 等。

要创建具有“first”、“last”和页码的分页控件,请设置像这样的 DataPager(其中 ListView1 是 ListView 控件的 ID):

<asp:DataPager ID="DataPager1" runat="server" 
   PagedControlID="ListView1" PageSize="25">
   <Fields>
      <asp:NextPreviousPagerField FirstPageText="first" ShowFirstPageButton="True" 
             ShowNextPageButton="False" ShowPreviousPageButton="False" />
      <asp:NumericPagerField />
      <asp:NextPreviousPagerField LastPageText="last" ShowLastPageButton="True" 
             ShowNextPageButton="False" ShowPreviousPageButton="False" />
   </Fields>
</asp:DataPager>

根据设计,DataPager 使用数据库中的整个结果集,但您可以通过缓存结果并在后续请求中使用该结果来提高性能。

希望这可以帮助。

You could use the DataPager control -- the only limitation is you have to use it with the ListView control, but you should be able to represent your data using the ListView control fairly easily because it is very flexible. You can set the DataSource of the ListView control to the result of your data result, whether that be a DataSet, Collection, Array, etc.

To create the paging controls with "first", "last", and page numbers, set up the DataPager like this (where ListView1 is the ID of your ListView control):

<asp:DataPager ID="DataPager1" runat="server" 
   PagedControlID="ListView1" PageSize="25">
   <Fields>
      <asp:NextPreviousPagerField FirstPageText="first" ShowFirstPageButton="True" 
             ShowNextPageButton="False" ShowPreviousPageButton="False" />
      <asp:NumericPagerField />
      <asp:NextPreviousPagerField LastPageText="last" ShowLastPageButton="True" 
             ShowNextPageButton="False" ShowPreviousPageButton="False" />
   </Fields>
</asp:DataPager>

By design, the DataPager uses the whole result set from the database, but you can improve the performance by caching the result and using that on the subsequent requests.

Hope this helps.

jJeQQOZ5 2024-07-23 00:22:12

iirc...在运行时动态添加控件有点棘手。 控制树必须在回发期间重建...但在加载视图状态之前(不确定在页面生命周期中的时间...但在页面加载之前)。 所以...你的问题是,当 ASP.NET 试图找出你的事件时,实际的原始控件尚未创建。

iirc... adding controls dynamically at runtime is a bit tricky. The control tree must be rebuilt during post back... but before viewstate is loaded (not sure when in the page life cycle... but way before page load). So... your problem is that by the time asp.net is trying to figure out your event the actual originating control has not yet been created.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文