Как использовать DataPager с страничным страничным сервером?

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

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

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

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

Ответы

Ответ 1

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

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

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

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

Ответ 2

Точно нужно, что вы сделали - подкачка SQL-сервера, использующая listview, datapager и источник данных 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

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

Все, что выделялось:

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

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

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 (оставил весь другой пух):

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

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

микрофон