代码之家  ›  专栏  ›  技术社区  ›  John

如何将数据寻呼机用于服务器端分页?

  •  13
  • John  · 技术社区  · 14 年前

    我正在尝试使用数据寻呼机进行服务器端分页。这是我的密码

    <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条。不知何故,它需要知道总共有1500条记录,而不是20条。DataPager具有属性totalRowCount,但这是只读的。

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

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

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

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

    我一直在寻找一些黑客来完成同样的事情,但似乎DataPager的totalRowCount是根据它绑定到的数据源中的实际项目数计算出来的。我觉得很奇怪,微软会同时创建一个listviewpageddatasource()类和一个datapager,而不是让它们一起正常工作,但这似乎就是所发生的事情。

    更新2(啊哈时刻?) 从.NET 2.0开始,似乎可以通过使用ObjectDatasource并自定义SelectCountMethod()来执行服务器端分页。我相信定制ObjectDatasource应该可以满足我的需求。嗯。我要去度周末,所以我要过几天看看这是否管用。敬请期待,真正的信徒。

    3 回复  |  直到 13 年前
        1
  •  3
  •   Bermo    14 年前

    使服务器端分页与DataPager一起工作的唯一方法似乎是使用 LinqDataSource 在您的标记中( 更新:这不是真的,见下文 ,并设置ListView的DataSourceID(如中所示)。 ScottGu's sample - step 6 ,而不是通过ListView数据源属性。但是我发现 trick 为了使这更可行,您可以通过代码隐藏而不是在标记中定义LinqDataSource查询(注意,本文说这将适用于任何数据源控件,但我认为情况并非如此)。

    这可能对您的情况没有任何帮助,因为我注意到,您调用的某种服务可能不会(也不应该)返回一个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控件来实现这一点-请参见 this article and download the sample . 虽然使用ObjectDataSource并不像使用LinqDataSource控件那么简单,但它使用的Magic Linq内容更少(相反,它使用映射到业务/数据层方法的一堆Magic字符串),并且允许为数据访问方法而不是iQuery暴露IEnumerable。

    不过,我从来没有真正喜欢在我的UI标记中嵌入任何类型的数据源控件(我认为这是必要的),所以我可能会避开DataPager控件,除了您在第一次更新中建议的小应用程序。

    约翰,我注意到的另一件事是,您试图将标准的ASP.NET服务器控件(依赖于ViewState)与pagedlist类结合起来,pagedlist类是为ASP.NET MVC应用程序开发的一个助手类。虽然这可能有效,但可能有更简单的路线。

        2
  •  10
  •   David    13 年前

    完全需要您所做的-使用listview、datapager和linq数据源的SQL Server分页。正如您所说,totalrowcount是只读的。还有setpageproperties方法可用于设置总行数,但也不适用于我。

    但我还是设法用这种方法骗了它。我有一个带有空项目模板的虚拟隐藏列表视图。寻呼机将指向此虚拟列表视图,而不是原始列表视图。然后,我们需要将虚拟ListView绑定到一个具有与原始数据源相同数量的项目的虚拟集合。这将确保正确呈现寻呼机。这是标记。

    <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
  •  0
  •   Jerzakie    14 年前

    约翰,我在这里做了一些概念证明,这样你就可以看到代码了。我把它做得尽可能基本,所以没有绒毛。请让我知道,如果有一些属性,你需要这是失踪,我将修改。

    突出的东西:

    1. 当您不使用数据源对象(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>
    

    享受吧,如果你还需要什么,请告诉我。

    迈克