Как использовать DataPager с пейджингом на стороне сервера? - PullRequest
13 голосов
/ 08 июля 2010

Я пытаюсь использовать DataPager для пейджинга на стороне сервера. Вот мой код

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

Код позади

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 взят из полезного поста RobConery http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/.

Проблема в том, что DataPager, похоже, использует свойство Count в ListView для определения общего количества записей, которое в данном случае равно 20. Почему-то нужно знать, что существует 1500, а не 20 записей. DataPager имеет свойство TotalRowCount, но оно доступно только для чтения.

Я никогда не видел пример DataPager с пейджингом на стороне сервера, но предполагал, что он мог бы выполнять пейджинг на стороне сервера, иначе что хорошего в атрибуте QueryStringField?

Мне известно, что вы можете создать нестандартное решение для пейджинга, используя методологию, подобную той, что использовала 4GuysFromRolla http://www.4guysfromrolla.com/articles/031506-1.aspx,, но сначала я хотел бы узнать, возможно ли решение с DataPager, прежде чем создавать собственное решение.

UPDATE Чем больше я на это смотрю, тем больше я прихожу к выводу, что это невозможно и что, к сожалению, DataPager - это элемент управления, предназначенный только для небольших веб-сайтов. То, что я хочу сделать, должно быть довольно простым, если элемент управления был построен правильно. Я хочу быть в состоянии сказать

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

Я искал какой-нибудь хак для достижения того же, но похоже, что TotalRowCount в пейджере вычисляется из фактического количества элементов в источнике данных, к которому он привязан. Мне кажется очень странным, что Microsoft создаст класс ListViewPagedDataSource () и DataPager одновременно и не даст им правильно работать вместе, но, похоже, именно это и произошло.

ОБНОВЛЕНИЕ 2 (АГА МОМЕНТ?) Похоже, что со времени .Net 2.0 стало возможно выполнять подкачку на стороне сервера, используя ObjectDataSource и настраивая SelectCountMethod (). Я считаю, что должна быть возможность настроить ObjectDataSource в соответствии с моими потребностями. Хммм. Я уезжаю на выходные, так что у меня будет пара дней, чтобы посмотреть, сработает ли это. Оставайтесь с нами, истинно верующие.

Ответы [ 3 ]

10 голосов
/ 14 сентября 2011

Точно нужно то, что вы сделали - пейджинг SQL-сервера с использованием списка, источника данных и источника данных linq. Как вы говорите, TotalRowCount только для чтения. Существует также метод SetPageProperties, который можно использовать для установки общего количества строк, но он также не работает для меня.

Однако мне удалось обмануть это. У меня есть фиктивный скрытый просмотр списка с пустым шаблоном элемента. Пейджер будет указывать на этот фиктивный просмотр списка, а не на исходный просмотр списка. Затем нам нужно привязать фиктивный список к фиктивной коллекции с тем же количеством элементов, что и в исходном источнике данных. Это обеспечит правильное отображение пейджера. Вот разметка.

<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>

и код позади

        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();

Протестировано с 100k записями. Работает угощение.

3 голосов
/ 16 июля 2010

Кажется, что единственный способ заставить серверную пейджинг работать с DataPager - это использовать LinqDataSource в вашей разметке ( обновление: это не так, см. Ниже ) и установитьDataSourceID вашего ListView (как в примере ScottGu - шаг 6 ), а не через свойство ListView DataSource.Однако я обнаружил, что существует трюк , чтобы сделать его более работоспособным, чтобы вы могли определить свой запрос LinqDataSource с помощью кода, а не разметки (обратите внимание, в статье говорится, что это будет работать с любым элементом управления DataSource, ноЯ не думаю, что это так).

Это, вероятно, не поможет в вашей ситуации, так как я заметил, что вы вызываете какую-то услугу, которая, вероятно, не будет (и не должна) возвращатьсяIQueryable результат, который необходим для этого, чтобы работать.В любом случае, если вам интересно ...

разметка aspx:

<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" />

код-позади:

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

Обратите внимание, MSDN указывает в отношении атрибута QueryStringField:

Установка этого свойства полезна, если вы хотите, чтобы все страницы данных былииндексируется поисковой системой.Это происходит из-за того, что элемент управления создает разные URL-адреса для каждой страницы данных.

Обновление: Фактически вы можете заставить это работать, используя элемент управления ObjectDataSource вместо элемента управления LinqDataSource - см. этой статьи и скачайте образец .Хотя использование ObjectDataSource не так просто, как использование элемента управления LinqDataSource, он использует меньше волшебных вещей linq (вместо этого он использует кучу волшебных строк, которые сопоставляются с методами уровня бизнес / данных) и позволяет использовать IEnumerable для вашего метода доступа к данным.вместо IQueryable.

Тем не менее, я никогда не любил встраивать какие-либо элементы управления DataSource в мою разметку пользовательского интерфейса (я считаю, что это необходимо), поэтому я бы, вероятно, держался подальше от элемента управления DataPager, за исключением небольшогоприложения, как вы предложили в первом обновлении.

Джон, еще одна вещь, которую я заметил, это то, что вы пытаетесь объединить стандартные серверные элементы управления Asp.Net (основанные на ViewState) с классом PagedList, который был разработан как вспомогательный класс для приложений Asp.Net Mvc.Хотя это потенциально может работать, могут быть более простые маршруты.

0 голосов
/ 16 июля 2010

Джон, я сделал небольшое доказательство концепции, чтобы вы могли увидеть код.Я сделал это как можно более простым, чтобы не было пуха.Пожалуйста, дайте мне знать, если вам нужен какой-то атрибут, который вам нужен, и я его исправлю.

Вещи, которые выделяются:

  1. Данные должны бытьпривязан к событию OnPreRender пейджера, когда вы не используете объект DataSource (xml, Sql, Access ...).Я довольно уверен, что это ваша проблема, потому что именно здесь у меня больше всего проблем.

  2. Viewstate должен быть включен на ListView и пейджер (этопо умолчанию)

Код-за:

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 (пропущены все остальные пух):

<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>

Наслаждайтесь, позвольтезнать, есть ли в этом что-то еще, что вам нужно.

mike

...