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

时间:2009-04-06 14:44:17

标签: asp.net pagination user-input

经典场景:获取用户输入,获取搜索结果并将其以页面形式显示给用户。然后我需要显示First,Next,Previous等按钮,并在viewstate中维护用户当前页面。一切都很好,工作正常。

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

渲染它们很简单。我在运行时生成一个linkbutton控件,添加带有页码的commandargument并为其添加一个处理程序,因此单击将被处理。然后我将它添加到占位符,并按预期显示。

但是......如果我还没有剃光头,我会拔出头发,每次都按照预期发射事件。

我应该怎么做,所以我的事件总是被连线并且能够在调用分页链接按钮时触发?

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

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

5 个答案:

答案 0 :(得分:2)

我建议不要使用LinkBut​​ton并建议使用Hyperlinks / QueryString参数。有几个原因:

  1. 如果没有链接按钮的视图状态开销,您的页面将更加高效。
  2. 如果这些是面向公众的页面,如果可以通过超链接访问(并通过搜索引擎索引),您将可以更好地索引所有页面。
  3. 您会发现它们更容易实现。没有事件管理等。
  4. 你会将你的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以获取页码。

答案 1 :(得分:1)

谢谢你的回答,伙计们。我首先尝试了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

答案 2 :(得分:0)

此代码有效(抱歉,它在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 />");
}

答案 3 :(得分:0)

您可以使用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使用数据库中的整个结果集,但您可以通过缓存结果并将其用于后续请求来提高性能。

希望这有帮助。

答案 4 :(得分:-1)

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