2010-07-08 57 views
13

我想使用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似乎使用ListView的Count属性来确定记录的总数,在这种情况下是20。不知何故,它需要知道有1,500个记录,而不是20个记录。 DataPager有一个属性TotalRowCount,但是这是只读的。

我从来没有见过使用服务器端分页的DataPager示例,但假定它可以执行服务器端分页,否则QueryStringField属性有什么好处?

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

UPDATE 我越是看这个,越觉得我来的结论是,这是不可能的,不幸的是,DataPager的是控制意味着只有小网站。如果控件构建正确,我想要做的事情应该非常简单。我想可以说

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

我一直在寻找一些黑客来完成同样的事情,但现在看来,DataPager的的TotalRowCount是从它绑定到数据源项目的实际数量计算。对我来说,看起来很奇怪,微软会同时创建一个ListViewPagedDataSource()类和一个DataPager,并且它们不会一起正确工作,但这似乎是发生了什么。

更新2(AHA时刻?) 看来,它已通过使用一个ObjectDataSource和定制SelectCountMethod是不可能做服务器端分页因为NET 2.0()。我相信应该可以自定义ObjectDataSource来满足我的需求。嗯。我要在周末外出,所以我需要几天的时间才能看到这是否有效。敬请关注,真正的信徒。

+0

你的应用程序是webform应用程序或Asp.Net MVC? – Sharique 2010-07-14 12:14:52

回答

3

这似乎让服务器端分页与DataPager的工作的唯一方法是使用LinqDataSource在您的标记(更新:这是不正确的,见下文),并设置ListView的DataSourceID(如ScottGu's sample - step 6),而不是通过ListView DataSource属性。但是我确实发现有一个trick可以使这更加可行,因此您可以通过代码隐藏而不是标记来定义您的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(); 
} 

注意,在问候MSDNQueryStringField属性:

如果您想让 的所有数据页都由搜索引擎索引,则设置此属性非常有用。发生此 是因为该控件为每个数据页面生成一个不同的URL 。

更新: INFACT你能得到这个使用ObjectDataSource控件,而不是LinqDataSource控件的工作 - 看this article and download the sample。虽然使用ObjectDataSource并不像使用LinqDataSource控件那么简单,但它使用的是更少的magic linq东西(而不是使用映射到业务/数据层方法的魔术字符串),并允许将IEnumerable暴露给您的数据访问方法而不是IQueryable。尽管如此,我从来没有真正喜欢在我的UI标记中嵌入任何类型的DataSource控件(我相信这是必要的),所以我可能会避开DataPager控件,除了小应用程序之外,正如您所建议的你的第一次更新。

约翰,我注意到的另一件事是,你试图与标准的Asp.Net服务器控件(依赖于ViewState)结合的PagedList类,它是作为Asp.Net Mvc应用程序的辅助类而开发的。虽然这可能有效,但可能有更简单的路线。

+0

感谢您的提示。微软将他们的数据访问层与应用层紧密结合的魅力在继续。 – John 2010-07-16 15:34:16

+1

谢谢,我来看看。这似乎是我所需要的。我真的不认为PagedList是一个MVC的东西,更像是一个Rob Conery的东西。在我找到PagedList之前,我之前的人一直在使用List GetFoobars(字符串id,out TotalRowCount)之类的方法。对我而言,PagedList只是一种很好的O-O做事的方式,而不是使用一种外观,这让我感觉不太舒服。 – John 2010-07-18 01:34:48

+0

我认为更简单的路线就是使用MVC开始,但团队尚未准备好转换此网站(我们正在开始使用其他地方)。我个人的感觉是,除了最简单的网站之外,MVC比网页形式要容易得多。 – John 2010-07-18 01:41:54

0

John,我在这里做了一点概念验证,以便您可以看到代码。我尽可能地做到这一点,所以没有绒毛。请让我知道,如果有这个属性,你需要缺少,我会修改。

事情站出来:

  1. 的数据需要,当你不使用数据源对象(XML,SQL,访问...)在寻呼机的OnPreRender事件被绑定。我是漂亮的确定这是你的问题,因为这是我遇到的最大麻烦。

  2. 视图状态必须在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> 

享受,让我知道如果有什么你需要的东西。

迈克

+0

不幸的是,这不是我所需要的。我需要做服务器端分页,也就是说,我在数据库中有1000条记录,但为了节省带宽,我只会从数据库中下载15条记录。假设我在数据库中有10,000条记录。我不想从数据库中获取所有10,000条记录,以便数据设置器可以正确计数。 – John 2010-07-16 14:37:34

+0

好吧,这很有道理,为什么这更复杂。你可能要做的就是创建一个像ICollection FooBarCollection这样的自定义集合,并重写Count方法,以便它返回你的整个计数。我不确定这是否会起作用,但可能您必须这样做才能欺骗DataPager,使其认为这里存在更多数据。 – Jerzakie 2010-07-16 16:20:44

10

确实需要你做的 - 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记录进行了测试。作品一种享受。

+0

有趣的解决方法。我现在通过去MVC路线避免了这个问题:-) – John 2011-10-31 01:11:18

+0

这个答案很棒...快速简单,并且可以获得数据寻呼机的所有好处。谢谢 – clamchoda 2017-11-03 00:37:31