2009-04-06 5 views
2

Классический сценарий: возьмите пользовательский ввод, получите результат поиска и отобразите его на страницах для пользователя. Затем мне нужно отображать кнопки для 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 
+0

@Kjensen - Я добавил альтернативу в своем ответе с использованием ретранслятора. Вы можете проверить это. – Keltex

ответ

2

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

Bind этот элемент управления в массив (или список) последовательных Целые (как многие из них есть страницы). Затем в вашей функции doPaging (как я ее называю) проверьте RepeaterCommandEventArgs.CommandArgument, чтобы получить номер страницы.

+0

Я думал об этом, но есть немало других элементов управления, в которых я использую viewstate, поэтому мне пришлось бы добавить 5-6 других элементов управления к querystring ... С другой стороны, я потратил полдня, пытаясь чтобы заставить это дерьмо работать ... Я подумаю об этом. :) – Kjensen

+0

@ Kjensen См. Мой альтернативный ответ выше. Я бы просто использовал ретранслятор. Затем вы просто CommandArgument, чтобы указать страницу #. – Keltex

-1

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

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 />"); 
} 
0

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

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

1

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

@ Kjensen: Спасибо, что принял мой ответ. Вы также можете заменить repPageNumbersTop_ItemDataBound на свойство LinkButton: Enabled = '<% # (Container.DataItem) .ToString <> Me.CurrentPage.ToString%>' (мой vb.net не слишком хорош .. .) – Keltex