13

我正在尝试使用 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 似乎使用 ListView 的 Count 属性来确定记录的总数,在本例中为 20。不知何故,它需要知道有 1,500 条记录,而不是 20 条记录。DataPager 有一个属性 TotalRowCount,但这是只读的。

我从未见过带有服务器端分页的 DataPager 示例,但假设它可以进行服务器端分页,否则 QueryStringField 属性有什么用?

我知道您可以使用 4GuysFromRolla 在这里http://www.4guysfromrolla.com/articles/031506-1.aspx所做的方法来执行自定义分页解决方案,但我首先想知道是否有 DataPager 的解决方案在创建自定义解决方案之前是可能的。

更新 我看的越多,我就越得出这样的结论,即这是不可能的,不幸的是,datapager 是一个仅适用于小型网站的控件。如果控件构建正确,我想要做的应该非常简单。我想能够说

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

我一直在寻找一些技巧来完成同样的事情,但似乎 datapager 的 TotalRowCount 是根据它绑定到的数据源中的实际项目数计算的。微软会同时创建一个 ListViewPagedDataSource() 类和一个 DataPager 并且没有让它们一起正常工作,这对我来说似乎很奇怪,但这似乎已经发生了。

UPDATE 2 (AHA MOMENT?) 自.Net 2.0 以来,似乎可以通过使用 ObjectDataSource 并自定义 SelectCountMethod() 来进行服务器端分页。我相信应该可以自定义 ObjectDataSource 以满足我的需要。嗯。我周末要离开,所以我需要几天时间看看这是否有效。请继续关注,真正的信徒。

4

3 回答 3

10

正是需要你所做的——利用 listview、datapager 和 linq 数据源的 SQL 服务器分页。正如您所说, 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();

用 10 万条记录对其进行了测试。工作一种享受。

于 2011-09-13T21:33:44.327 回答
3

似乎让服务器端分页与 DataPager 一起使用的唯一方法是LinqDataSource在您的标记中使用 a (更新:这不是真的,见下文),并设置您的 ListView 的 DataSourceID (如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。

尽管如此,我从来没有真正喜欢在我的 UI 标记中嵌入任何类型的 DataSource 控件(我相信这是必要的),所以我可能会避开 DataPager 控件,除了您在第一次更新中建议的小型应用程序。

约翰,我注意到的另一件事是,您正试图将标准 Asp.Net 服务器控件(依赖于 ViewState)与作为 Asp.Net Mvc 应用程序的帮助类开发的 PagedList 类结合起来。虽然这可能会奏效,但可能有更简单的路线可供选择。

于 2010-07-16T14:20:31.547 回答
0

约翰,我在这里做了一点概念证明,这样你就可以看到代码。我把它做得尽可能基本,所以没有绒毛。请让我知道是否缺少您需要的某些属性,我将进行修改。

突出的事情:

  1. 当您不使用 DataSource 对象(xml、Sql、Access...)时,数据需要绑定在寻呼机的 OnPreRender 事件上。我确定这是您的问题,因为这是我遇到最大麻烦的地方。

  2. 必须在 ListView 和寻呼机上启用 Viewstate(默认情况下)

代码隐藏:

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>

享受吧,让我知道您是否还需要其他东西。

麦克风

于 2010-07-16T04:10:04.710 回答