Реализация кликабельных номеров страниц в результатах поиска - PullRequest
2 голосов
/ 06 апреля 2009

Классический сценарий: взять пользовательский ввод, получить результат поиска и отобразить его на страницах для пользователя. Затем мне нужно отобразить кнопки для First, Next, Previous и т. Д., И я поддерживаю текущую страницу пользователя в viewstate. Все хорошо, отлично работает.

Тогда мне нужно реализовать кликабельные номера страниц, т.е. 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

Ответы [ 5 ]

2 голосов
/ 06 апреля 2009

Я собираюсь рекомендовать против LinkButton и рекомендовать вместо этого параметры 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...

Альтернатива: Если вы хотите использовать LinkButton, вы можете подумать о том, чтобы поместить одну LinkButton в ретранслятор. Тогда единственное событие, о котором вам нужно беспокоиться, - это событие 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 голос
/ 07 апреля 2009

Спасибо за ответы, ребята. Сначала я попробовал 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
0 голосов
/ 07 апреля 2009

Вы можете использовать элемент управления DataPager - единственное ограничение заключается в том, что вы должны использовать его с элементом управления ListView, но вы должны быть в состоянии представить свои данные с помощью элемента управления ListView, потому что он очень гибкий. Вы можете установить DataSource элемента управления ListView на результат результата ваших данных, будь то DataSet, Collection, Array и т. Д.

Чтобы создать элементы управления подкачкой с «первым», «последним» и номерами страниц, настройте DataPager следующим образом (где ListView1 - это идентификатор элемента управления ListView):

<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 использует весь набор результатов из базы данных, но вы можете улучшить производительность, кэшируя результат и используя его в последующих запросах.

Надеюсь, это поможет.

0 голосов
/ 06 апреля 2009

Этот код работает (извините, он в 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 />");
}
0 голосов
/ 06 апреля 2009

iirc ... динамическое добавление элементов управления во время выполнения немного сложно. Дерево элементов управления должно быть перестроено во время обратной отправки ... но до загрузки viewstate (не уверен, когда в жизненном цикле страницы ... но задолго до загрузки страницы). Итак ... ваша проблема в том, что к тому времени, когда asp.net пытается выяснить ваше событие, фактический исходный элемент управления еще не создан.

...