少なくともさらなる探求の良い出発点になり得るものがあると思います。いくつかのアイデアに基づいた方法を説明するために、サンプルを作成しました(さらに下に)。
- ページングを機能させるには、
ObjectDatasource
を使用する必要があります。そうGridView
すれば、合計で何行あるかを知ることができます。
ObjectDataSource
フェッチしたデータが利用可能になったら、そのデータにアクセスできるようにする方法が必要です。
2. を解決するために思いついたアイデアは、GridView
が配置されているページが実装できるインターフェイスを定義することでした。次に、ObjectDataSource
データを取得するための呼び出しをページ自体に中継するクラスを使用できます。呼び出しが早すぎると、空のデータが返されますが、後で実際のデータに置き換えられます。
いくつかのコードを見てみましょう。
これが私のaspxファイルです:
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeFile="GridViewTest.aspx.cs" Inherits="GridViewTest" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="Server">
<asp:GridView ID="jobsGv" runat="server" AutoGenerateColumns="false" AllowPaging="true"
PageSize="13" OnPageIndexChanging="jobsGv_PageIndexChanging" DataSourceID="jobsDataSource">
<Columns>
<asp:TemplateField HeaderText="Job Id">
<ItemTemplate>
<asp:Literal ID="JobId" runat="server" Text='<%# Eval("JobId") %>'></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Job description">
<ItemTemplate>
<asp:Literal ID="Description" runat="server" Text='<%# Eval("Description") %>'></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Min level">
<ItemTemplate>
<asp:Literal ID="MinLvl" runat="server" Text='<%# Eval("MinLvl") %>'></asp:Literal>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="jobsDataSource" runat="server" TypeName="JobObjectDs" CacheDuration="0"
SelectMethod="GetJobs" EnablePaging="True" SelectCountMethod="GetTotalJobsCount">
</asp:ObjectDataSource>
<asp:Button ID="button" runat="server" OnClick="button_Click" Text="Test postback" />
</asp:Content>
そして背後にあるコード:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
public partial class GridViewTest : System.Web.UI.Page, IJobDsPage
{
bool gridNeedsBinding = false;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gridNeedsBinding = true;
}
}
protected void jobsGv_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
var gv = (GridView)sender;
newPageIndexForGv = e.NewPageIndex;
gridNeedsBinding = true;
}
private int newPageIndexForGv = 0;
protected void Page_PreRendercomplete(object sender, EventArgs e)
{
if (gridNeedsBinding)
{
// fetch data into this.jobs and this.totalJobsCount to simulate
// that data has just become available asynchronously
JobDal dal = new JobDal();
jobs = dal.GetJobs(jobsGv.PageSize, jobsGv.PageSize * newPageIndexForGv).ToList();
totalJobsCount = dal.GetTotalJobsCount();
//now that data is available, bind gridview
jobsGv.DataBind();
jobsGv.SetPageIndex(newPageIndexForGv);
}
}
#region JobDsPage Members
List<Job> jobs = new List<Job>();
public IEnumerable<Job> GetJobs()
{
return jobs;
}
public IEnumerable<Job> GetJobs(int maximumRows, int startRowIndex)
{
return jobs;
}
int totalJobsCount;
public int GetTotalJobsCount()
{
return totalJobsCount;
}
#endregion
protected void button_Click(object sender, EventArgs e)
{
}
}
そして最後に、それを結び付けるいくつかのクラスがあります。これらを App_Code の 1 つのコード ファイルにまとめました。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// Simple POCO to use as row data in GridView
/// </summary>
public class Job
{
public int JobId { get; set; }
public string Description { get; set; }
public int MinLvl { get; set; }
//etc
}
/// <summary>
/// This will simulate a DAL that fetches data
/// </summary>
public class JobDal
{
private static int totalCount = 50; // let's pretend that db has total of 50 job records
public IEnumerable<Job> GetJobs()
{
return Enumerable.Range(0, totalCount).Select(i =>
new Job() { JobId = i, Description = "Descr " + i, MinLvl = i % 10 }); //simulate getting all records
}
public IEnumerable<Job> GetJobs(int maximumRows, int startRowIndex)
{
int count = (startRowIndex + maximumRows) > totalCount ? totalCount - startRowIndex : maximumRows;
return Enumerable.Range(startRowIndex, count).Select(i =>
new Job() { JobId = i, Description = "Descr " + i, MinLvl = i % 10 }); //simulate getting one page of records
}
public int GetTotalJobsCount()
{
return totalCount; // simulate counting total amount of rows
}
}
/// <summary>
/// Interface for our page, so we can call methods in the page itself
/// </summary>
public interface IJobDsPage
{
IEnumerable<Job> GetJobs();
IEnumerable<Job> GetJobs(int maximumRows, int startRowIndex);
int GetTotalJobsCount();
}
/// <summary>
/// This will be used by our ObjectDataSource
/// </summary>
public class JobObjectDs
{
public IEnumerable<Job> GetJobs()
{
var currentPageAsIJobDsPage = (IJobDsPage)HttpContext.Current.CurrentHandler;
return currentPageAsIJobDsPage.GetJobs();
}
public IEnumerable<Job> GetJobs(int maximumRows, int startRowIndex)
{
var currentPageAsIJobDsPage = (IJobDsPage)HttpContext.Current.CurrentHandler;
return currentPageAsIJobDsPage.GetJobs(maximumRows, startRowIndex);
}
public int GetTotalJobsCount()
{
var currentPageAsIJobDsPage = (IJobDsPage)HttpContext.Current.CurrentHandler;
return currentPageAsIJobDsPage.GetTotalJobsCount();
}
}
それで、それはすべて何をしますか?
さて、IJobDsPage
インターフェイスを実装している Page があります。ページには、 with idGridView
を使用している があります。つまり、クラスを使用してデータをフェッチします。そして、そのクラスは、現在実行中の Page を から取得し、それをインターフェイスにキャストして、Page のインターフェイス メソッドを呼び出します。ObjectDataSource
jobsDataSource
JobObjectDs
HttpContext
IJobDsPage
その結果、データを取得するためにページ内のメソッドを呼び出すGridView
を使用するが得られます。ObjectDataSource
これらのメソッドの呼び出しが早すぎると、空のデータが返されます (new List<Job>()
対応する合計行数が 0 になります)。ただし、データが利用可能なページ処理の段階に達したときに GridView を手動でバインドしているため、これは問題ありません。
全体として、私のサンプルはうまくいきますが、素晴らしいとは言えません。現状では、はリクエスト中に関連付けられたメソッドを複数回ObjectDataSource
呼び出します。ただし、実際のデータの取得は 1 回しか行われないSelect
ため、最初に思ったほど悪くはありません。また、次のページに遷移するときに同じデータに 2 回バインドされます。GridView
そのため、改善の余地があります。しかし、それは少なくとも出発点です。