2010-07-08 10 views
13

Próbuję użyć programu DataPager do stronicowania po stronie serwera. Oto mój kodJak używać programu DataPager z funkcją stronicowania po stronie serwera?

<asp:DataPager ID="pgrFooBars" PagedControlID="lvFooBars" 
    QueryStringField="page" runat="server" > 
<Fields> 
    <asp:NumericPagerField /> 
</Fields> 
</asp:DataPager> 

Code Behind pochodzi RobConery za post http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/

protected void Page_Load(object sender, EventArgs e) 
{ 
    ConfigureBlogPostListView(); 
} 

private void ConfigureBlogPostListView() 
{ 
    int pageNum; 
    int.TryParse(Request.Params["page"], out pageNum); 
    int pageSize = 20; 

    PagedList<IFooBar> FooBars = FooService.GetPagedFooBars(
     new PagingSettings(pageNum, pageSize)); 

    ListViewPagedDataSource ds = new ListViewPagedDataSource(); 
    ds.AllowServerPaging = true; 
    ds.DataSource = FooBars; 
    ds.MaximumRows = pageSize; 
    ds.StartRowIndex = pageNum; 
    //TotalCount is the total number of records in the entire set, not just those loaded. 
    ds.TotalRowCount = FooBars.TotalCount; 

    lvFooBars.DataSource = ds; 
    lvFooBars.DataBind(); 

    pgrFooBars.PageSize = pageSize; 
    pgrFooBars.SetPageProperties(pageNum, FooBars.TotalCount, true); 
} 

PagedList.

Problem polega na tym, że DataPager wydaje się używać właściwości Count z ListView do określenia całkowitej liczby rekordów, która w tym przypadku wynosi 20. W pewnym sensie musi wiedzieć, że istnieje 1500 rekordów, a nie 20 łącznie . DataPager ma właściwość TotalRowCount, ale jest to tylko do odczytu.

Nigdy nie widziałem przykład DataPager z stronicowania po stronie serwera, ale założyć, że można wykonać stronicowania po stronie serwera, w przeciwnym razie co dobre jest atrybut QueryStringField?

Jestem świadomy, że można zrobić niestandardowe rozwiązanie stronicowania przy użyciu metodologii, takiej jak 4GuysFromRolla, tutaj http://www.4guysfromrolla.com/articles/031506-1.aspx, ale najpierw chciałbym wiedzieć, czy rozwiązanie z DataPager jest możliwe przed stworzeniem niestandardowego rozwiązania.

UPDATE Im więcej patrzę, tym bardziej, że wracam do wniosku, że nie jest to możliwe i że, niestety, datapager jest kontrola przeznaczona wyłącznie dla małych stron internetowych. To, co chcę zrobić, powinno być naprawdę proste, jeśli kontrola została poprawnie zbudowana. Chcę móc powiedzieć

dpFooBars.TotalRowCountComputed = false; 
dpFooBars.TotalRowCount = AnyNumberThatISoChoose; 

Szukałem jakiegoś włamania się osiągnąć to samo, ale wydaje się, że datapager za TotalRowCount obliczany jest od faktycznej liczby elementów w źródle danych, że to wiąże się z . Wydaje mi się bardzo dziwne, że Microsoft utworzyłby w tym samym czasie klasę ListViewPagedDataSource() i DataPager, ale nie sprawiłaby, że działałyby one poprawnie razem, ale wydaje się, że tak się stało.

UPDATE 2 (AHA chwili?) Wydaje się, że to było możliwe do zrobienia po stronie serwera stronicowania od .NET 2.0 przy użyciu ObjectDataSource i dostosowywania SelectCountMethod(). Uważam, że powinno być możliwe dostosowanie ObjectDataSource do moich potrzeb. Hmmm. Wyjeżdżam na weekend, więc będzie to dla mnie kilka dni, aby sprawdzić, czy to działa. Bądźcie czujni, prawdziwie wierzący.

+0

Jesteś aplikacją webform lub Asp.Net MVC? – Sharique

Odpowiedz

3

Wydaje się, że jedynym sposobem, aby po stronie serwera stronicowania do współpracy z DataPager jest użycie LinqDataSource w znacznikach (zmiana: to nie jest prawda, patrz poniżej) i ustaw DataSourceID twojego ListView (jak w ScottGu's sample - step 6), a nie za pośrednictwem właściwości ListView DataSource. Jednak odkryłem, że istnieje trick, aby uczynić to bardziej użytecznym, dzięki czemu możesz zdefiniować swoje zapytanie LinqDataSource za pomocą kodu, zamiast w znaczniku (uwaga, artykuł mówi, że będzie działać z dowolnym kontrolerem DataSource, ale nie sądzę, że tak jest).

Prawdopodobnie nie będzie to pomocne dla twojej sytuacji, ponieważ zauważyłem, że twoje wezwanie jest usługą, która prawdopodobnie nie będzie (i nie powinna) zwracać wyniku IQueryable, który jest niezbędny, aby to zadziałało. Tutaj jest to w każdym razie w przypadku, jesteś zainteresowany ...

aspx markup:

<asp:ListView ID="lvFooBars" DataSourceID="dsLinq" ....> 
    ...... 
</asp:ListView> 

<asp:DataPager ID="pgrFooBars" PagedControlID="lvFooBars" 
    QueryStringField="page" runat="server" > 
<Fields> 
    <asp:NumericPagerField /> 
</Fields> 
</asp:DataPager> 

<asp:LinqDataSource id="dsLinq" runat="server" OnSelecting="dsLinq_Selecting" /> 

kod z opóźnieniem:

protected void dsLinq_Selecting(object sender, LinqDataSourceSelectEventArgs e) 
{ 
    //notice this method on FooService requires no paging variables 
    e.Result = FooService.GetIQueryableFooBars(); 
} 

Uwaga, MSDN członkowskie w odniesieniu do atrybut QueryStringField:

Ustawienie tej właściwości jest przydatne, jeśli chcesz wszystkie strony danych indeksowane przez wyszukiwarkę. Ta występuje, ponieważ formant generuje inny adres URL dla każdej strony danych.

Aktualizacja: rzeczywiście można uzyskać to do pracy za pomocą kontrolki ObjectDataSource, zamiast sterowania LinqDataSource - patrz this article and download the sample. Podczas korzystania z ObjectDataSource nie jest tak proste, jak przy użyciu kontrolki LinqDataSource, to używa mniej magicznych rzeczy linq (zamiast tego używa kuponów magicznych ciągów mapujących do metod biznesowych/warstw danych) i pozwala na ekspozycję IEnumerable dla twojej metody dostępu do danych zamiast IQueryable.

Nadal, nigdy nie byłem fanem osadzania jakiejkolwiek kontroli DataSource w moim znaczniku UI (uważam, że jest to konieczne), więc prawdopodobnie omijałbym kontrolę DataPager z wyjątkiem małych aplikacji, jak sugerowałeś w twoja pierwsza aktualizacja.

John, jeszcze jedna rzecz, którą zauważyłem, to że próbujesz poślubić standardowe kontrolki serwera Asp.Net (które polegają na ViewState) z klasą PagedList, która została opracowana jako klasa pomocnicza dla aplikacji ASP.Net Mvc.Chociaż może to potencjalnie zadziałać, mogą istnieć prostsze trasy do podjęcia.

+0

Dzięki za napiwek. Fascynacja Microsoftu ścisłym łączeniem warstwy dostępu do danych z warstwą aplikacji trwa. – John

+1

Dzięki, popatrzę. Wygląda na to, czego potrzebuję. Naprawdę nie uważałem PagedList za tak dużą rzecz MVC, po prostu o coś z Rob Conery. Zanim znalazłem PagedList, ludzie przede mną stosowali metody takie jak List GetFoobars (id łańcucha, out TotalRowCount). Dla mnie PagedList był po prostu dobrym sposobem na zrobienie czegoś, zamiast używania outu, z którym nigdy nie czuję się swobodnie. – John

+0

Myślę, że prostszą drogą byłoby po prostu użycie MVC na początek, ale zespół nie jest jeszcze gotowy do konwersji tej strony (zaczynamy używać gdzie indziej). Moim osobistym odczuciem jest to, że MVC jest znacznie łatwiejsze niż formularze internetowe w czymkolwiek poza najprostszymi stronami. – John

0

John, przedstawiłem tutaj mały dowód na to, że możesz zobaczyć kod. Zrobiłem to tak podstawowe, jak to możliwe, więc nie ma puchu. Daj mi znać, jeśli jest jakiś atrybut tego, czego potrzebujesz, którego brakuje, a ja to zmienię.

Rzeczy, które się wyróżniał:

  1. dane muszą być związana na razie OnPreRender na pager, gdy nie używasz obiektu DataSource (XML, SQL, dostęp ...). Jestem ładna na pewno jest to twoja sprawa, ponieważ właśnie tam miałem najwięcej problemów.

  2. stan wyświetlania musi być włączona ListView i pagera (jest domyślnie)

Code-Behind:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class _Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (!Page.IsPostBack) 
     { 
      this.BindListData(); 
     } 
    } 

    protected void dp_PreRender(object sender, EventArgs e) 
    { 
     this.BindListData(); 
    } 

    protected void BindListData() 
    { 
     List<Nums> n = new List<Nums>(); 
     for (int i = 0; i <= 100; i++) 
     { 
      n.Add(new Nums { Num1 = i, Num2 = i * 3 }); 
     } 

     this.lvMyGrid.DataSource = n; 
     this.lvMyGrid.DataBind(); 
    } 
} 

public class Nums 
{ 
    public int Num1 { get; set; } 
    public int Num2 { get; set; } 
} 

ASPX (pominąć wszystkie inne puch):

<asp:DataPager OnPreRender="dp_PreRender" runat="server" ID="dpMyPager" QueryStringField="page" PagedControlID="lvMyGrid" PageSize="15"> 
    <Fields> 
     <asp:NumericPagerField /> 
    </Fields> 
</asp:DataPager> 

<asp:ListView runat="server" ID="lvMyGrid" DataKeyNames="Num1"> 
    <LayoutTemplate> 
     <asp:Literal runat="server" ID="itemPlaceholder" /> 
    </LayoutTemplate> 
    <ItemTemplate> 
     <div style="border: 1px solid red; padding: 3px; margin: 5px; float: left; clear: both;"> 
     <%# Eval("Num1") %> : <%# Eval("Num2") %> 
     </div> 
    </ItemTemplate> 
</asp:ListView> 

Ciesz się, daj mi znać, jeśli jest coś jeszcze w tym, czego potrzebujesz.

Mike

+0

Niestety, to nie jest to, czego potrzebuję. Muszę wykonać stronicowanie po stronie serwera, tj. Mam łącznie 1000 rekordów w bazie danych, ale aby zaoszczędzić przepustowość, pobieram tylko 15 rekordów z bazy danych. Powiedzmy, że mam 10 000 rekordów w bazie danych. Nie chcę pobierać wszystkich 10 000 rekordów z bazy danych tylko po to, aby serwer danych mógł uzyskać prawidłową liczbę. – John

+0

OK, to ma sens, dlaczego jest to bardziej skomplikowane. Najprawdopodobniej będziesz musiał utworzyć niestandardową kolekcję, taką jak ICollection FooBarCollection, i zastąpić metodę Count, aby zwrócić całą liczbę. Nie jestem pewien, czy to zadziała, czy nie, ale prawdopodobnie będziesz musiał zrobić coś takiego, aby oszukać DataPagera w przekonaniu, że jest tam więcej danych, niż jest. – Jerzakie

10

Dokładnie potrzebne, co zrobiłeś - stronicowanie serwera SQL z wykorzystaniem listview, datapagera i źródła danych linq. Jak mówisz TotalRowCount jest readonly. Istnieje również metoda SetPageProperties, która może być użyta do ustawienia całkowitej liczby wierszy, ale to też nie zadziałało.

Udało mi się jednak oszukać w ten sposób. Mam fałszywą ukrytą listę widoków z pustym szablonem przedmiotu. Pager będzie wskazywał na ten fałszywy widok listy zamiast oryginalnego listview. Następnie musimy powiązać atrapowy widok listy z kolekcją fikcyjną z taką samą liczbą elementów, jak w oryginalnym źródle danych. Zapewni to poprawne renderowanie pagera. Oto znacznik.

<asp:DataPager ID="pdPagerBottom" runat="server" PagedControlID="lvDummy" PageSize="5" QueryStringField="page"> 
<Fields> 
    <asp:NumericPagerField ButtonType="Link" RenderNonBreakingSpacesBetweenControls="true" NextPageText="Next" PreviousPageText="Previous" ButtonCount="40" /> 
</Fields> 
</asp:DataPager> 

<asp:ListView ID="lvDummy" runat="server" Visible="false"> 
<ItemTemplate></ItemTemplate> 
</asp:ListView> 

<asp:ListView ID="lvPropertyList" runat="server">...</asp:ListView> 

i kod za

 var datasourceQuery = context.Properties.OrderBy(x => x.PropertyID).Skip(pdPagerBottom.StartRowIndex).Take(pdPagerBottom.PageSize); 

     this.lvPropertyList.DataSource = datasourceQuery; 
     this.lvPropertyList.DataBind(); 

     this.lvDummy.DataSource = new List<int>(Enumerable.Range(0, context.Properties.Count())); 
     this.lvDummy.DataBind(); 

testowałem to z 100k rekordów. Działa jak smakołyk.

+0

Interesujące obejście. Teraz unikam problemu po prostu kierując się trasą MVC :-) – John

+0

Ta odpowiedź jest niesamowita ... szybka i łatwa i zapewnia wszystkie korzyści związane z pageriem danych. Dziękuję Ci – clamchoda

Powiązane problemy