亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

創(chuàng)建用于 ASP.NET 的分頁程序控件[MSDN]

2019-11-17 05:00:42
字體:
供稿:網(wǎng)友
摘要:解決向任何 asp.net 控件添加分頁功能的問題。還為開發(fā)復合 ASP.NET 控件提供了很多有用的提示和技巧。 下載本文的源代碼(英文)。(請注重,在示例文件中,程序員的注釋使用的是英文,本文中將其譯為中文是為了便于讀者理解。)從程序員的角度來看,Microsoft® SQL Server™ 查詢的最大缺陷之一就是返回的行數(shù)通常比應(yīng)用程序的用戶界面實際可以容納的行數(shù)要多得多。這種尷尬情形經(jīng)常將開發(fā)人員陷于困境。開發(fā)人員是應(yīng)該創(chuàng)建一個非常長的頁面,讓用戶花時間去滾動瀏覽,還是應(yīng)該通過設(shè)置一個手動分頁機制來更好地解決這個問題? 哪種解決方案更好,在很大程度上取決于要檢索的數(shù)據(jù)的特性。由多個項目(如搜索結(jié)果)組成的較長列表,最好通過各頁大小相等、每頁相對較短的多個頁面顯示。由單個項目(如文章的文本)組成的較長列表,假如整個插入在一個頁面中,使用起來會更方便。最后得出的分析結(jié)果是,應(yīng)該根據(jù)應(yīng)用程序的總體用途來做決定。那么,Microsoft® ASP.NET 是如何解決數(shù)據(jù)分頁問題的呢?ASP.NET 提供了功能強大的數(shù)據(jù)綁定控件,以便將查詢結(jié)果格式化為 Html 標記。但是,這些數(shù)據(jù)綁定控件中只有一種控件(即 DataGrid 控件)本來就支持分頁。其他控件(如 DataList、Repeater 或 CheckBoxList)則不支持分頁。這些控件及其他列表控件不支持分頁,不是因為它們在結(jié)構(gòu)上不支持分頁,而是因為它們與 DataGrid 不同,不包含任何處理分頁的特定代碼。但是,處理分頁的代碼是相當樣板化的,可以添加到所有這些控件中。 Scott Mitchell 在最近的一篇題目為“Creating a Pageable, Sortable DataGrid”(英文)的文章中,介紹了 DataGrid 分頁。該文還引用了 Web 上的其他有用信息,為您提供了有關(guān)網(wǎng)格分頁基礎(chǔ)知識和其他信息。假如想查看如何使 DataList 控件可以進行分頁的示例,可以查看此文章(英文)。該文演示了如何創(chuàng)建一個自定義的 DataList 控件,該控件具有當前索引和頁面大小屬性,并可以啟動頁面更改事件。 同樣的代碼也可以用于滿足其他列表控件(如 ListBox 和 CheckBoxList)的分頁需要。不過,向各個控件添加分頁功能實際上并不是一種非常好的做法,因為,如上所述,分頁代碼是相當樣板化的。因此,對于聰明的程序員來說,有什么方法比使用一種新的通用分頁程序控件來實現(xiàn)所有這些控件的分頁功能更好的呢?本文中將建立一個分頁程序控件,它將使合作者列表控件能夠?qū)?SQL Server 的查詢結(jié)果進行分頁。該控件名為 SqlPager,它支持兩種類型的合作者控件 - 列表控件和基礎(chǔ)數(shù)據(jù)列表控件。SqlPager 控件的顯著特點SqlPager 控件是一個 ASP.NET 復合控件,包含一個單行表格。該行又包含兩個單元格 - 導航條和頁面描述符。該控件的用戶界面呈條形,理想情況下,其寬度與合作者控件的寬度相同。導航條部分提供了可單擊的元素,以便在頁面之間移動;頁面描述符部分為用戶提供了有關(guān)當前顯示的頁面的一些反饋信息。 創(chuàng)建用于 ASP.NET 的分頁程序控件[MSDN](圖一)圖 1:Visual Studio .NET 網(wǎng)頁設(shè)計器中顯示的 SqlPager 控件與 DataGrid 控件的嵌入式分頁程序一樣,SqlPager 控件具有兩種導航模式,即下一頁/上一頁和數(shù)字頁面。此外,其非凡屬性 PagerStyle 使您能夠選擇更方便的樣式。該控件與列表控件協(xié)同工作。您可以通過 ControlToPaginate 字符串屬性為分頁程序指定一個這樣的合作者控件。 SqlPager1.ControlToPaginate = "ListBox1"; 一般情況下,分頁程序首先獲取 SQL Server 的查詢結(jié)果,預(yù)備一個適當?shù)挠涗涰撁?,然后通過合作者控件的 DataSource 屬性顯示該頁面。當用戶單擊以查看新頁面時,分頁程序?qū)z索請求的數(shù)據(jù)并再次通過合作者控件來顯示數(shù)據(jù)。分頁機制對于列表控件是完全透明的。列表控件的數(shù)據(jù)源是通過編程方式進行更新的,任何時候都只包含適合當前頁面的記錄。 控件的分頁引擎具有多個 public 屬性,如 CurrentPageIndex、ItemsPerPage 和 PageCount,通過這些屬性來獲取并設(shè)置當前頁面的索引、每個頁面的大小以及要顯示的頁面的總數(shù)。分頁程序治理數(shù)據(jù)檢索和分頁所需的任何邏輯。 SelectCommand 屬性設(shè)置獲取數(shù)據(jù)所用的命令文本。ConnectionString 屬性定義數(shù)據(jù)庫的名稱和位置以及連接憑據(jù)。執(zhí)行查詢時采用的方式取決于 PagingMode 屬性的值。該屬性的可能值為與其同名的 PagingMode 枚舉的值 - Cached 和 NonCached。假如選擇 Cached 選項,則將使用數(shù)據(jù)適配器和 DataTable 對象檢索整個結(jié)果集??梢赃x擇將結(jié)果集放置在 ASP.NET 的 Cache 對象中,該結(jié)果集可以重復使用直到過期。假如選擇 NonCached 選項,則查詢只檢索適合當前頁面的記錄。這時,ASP.NET 的 Cache 中不放置任何數(shù)據(jù)。NonCached 模式與 DataGrid 控件的自定義分頁模式幾乎相同。
下表列出 SqlPager 控件的全部編程接口。表 1:SqlPager 控件的編程接口名稱類型說明CacheDuration屬性指示數(shù)據(jù)在 ASP.NET 的緩存中保留的秒數(shù)。只用于 Cached 模式。默認值為 60 秒。ConnectionString屬性用來訪問所選擇的 SQL Server 數(shù)據(jù)庫的連接字符串。ControlToPaginate屬性同一個 .aspx 頁面中的控件 ID,它將顯示分頁程序檢索的記錄頁面。這是合作者控件。CurrentPageIndex屬性獲取并設(shè)置基于 0 的頁面索引。 ItemsPerPage屬性獲取并設(shè)置每頁要顯示的記錄數(shù)量。默認值為每頁顯示 10 個項目。PagerStyle屬性該值指示分頁程序用戶界面的樣式。它可以為 PagerStyle 枚舉值:NextPRev 和 NumericPages 之一。在 NextPrev 模式中,將顯示 VCR 式的按鈕,來轉(zhuǎn)到第一頁、上一頁、下一頁和最后一頁。而在 NumericPages 模式中,將顯示一個下拉列表,列出所有可用頁面的索引。PagingMode屬性該值指示檢索數(shù)據(jù)的方式。它可以為 PagingMode 枚舉值:Cached 和 NonCached 之一。假如為 Cached,則將使用數(shù)據(jù)適配器,且整個結(jié)果集將臨時放置在 ASP.NET 緩存中。假如為 NonCached,則只檢索當前頁面中的記錄。在這種情況下,不進行緩存。SelectCommand屬性用來進行查詢的命令文本。最好為 SELECT-FROM-WHERE 形式。不支持 ORDER BY 子句。排序是通過 SortField 屬性另外指定的。SortField屬性用來排序的字段的名稱。此字段用于為查詢提供動態(tài)的 ORDER BY 子句。排序是由 SQL Server 執(zhí)行的。 ClearCache方法刪除存儲在 ASP.NET 緩存中的任何數(shù)據(jù)。PageIndexChanged事件默認事件,當分頁程序移動到另一個頁面時發(fā)生。事件的數(shù)據(jù)結(jié)構(gòu)為 PageChangedEventArgs 類,包含舊頁面和新頁面的索引。由于 SqlPager 控件繼續(xù)了 WebControl,因此它也具有很多與 UI 相關(guān)的屬性來治理字體、邊框和顏色。 生成 SqlPager 控件將作為復合控件來生成 SqlPager 控件并讓其繼續(xù) WebControl 類。復合控件是 ASP.NET 服務(wù)器控件所特有的,它是由一個或多個服務(wù)器控件組成。 public class SqlPager : WebControl, INamingContainer{ ... } 除非生成完全自定義的控件或擴展現(xiàn)有的控件,否則,創(chuàng)建新控件時,大多數(shù)時間實際上是在生成復合控件。要創(chuàng)建 SqlPager,組合一個 Table 控件,并根據(jù)分頁程序的樣式,組合幾個 LinkButton 控件或者一個 DropDownList 控件。 生成復合控件時,需要注重幾條原則。首先,需要覆蓋 CreateChildControls protected 方法。CreateChildControls 方法是從 Control 繼續(xù)來的,當服務(wù)器控件為了顯示而要創(chuàng)建子控件時或在返回后,將調(diào)用此方法。 protected override void CreateChildControls(){ // 清除現(xiàn)有的子控件及其 ViewState Controls.Clear(); ClearChildViewState(); // 生成控件樹 BuildControlHierarchy();} 覆蓋此方法時,需要執(zhí)行幾項重要的操作。創(chuàng)建并初始化任何所需的子控件實例并將它們添加到父控件的 Controls 集合中。但是,生成新控件樹之前,應(yīng)該刪除任何現(xiàn)有的子控件并清除子控件可能留下的任何 ViewState 信息。 復合組件還需要實現(xiàn) INamingContainer 接口,以便 ASP.NET 運行時可以為其創(chuàng)建一個新的命名范圍。這就確保了復合控件中的所有控件都具有唯一的名稱。這還將確保能夠自動處理子控件的返回數(shù)據(jù)。 對于 SqlPager 控件來說,成為命名容器非常重要。事實上,SqlPager 包含一些 LinkButton 控件,并且需要獲取并處理其單擊事件以便導航頁面。正如 ASP.NET 頁面中的任何其他控件一樣,LinkButton 也被賦予了一個 ID,用于標識處理返回事件的控件。 處理返回事件時,ASP.NET 運行時試圖查找事件的目標 ID 與主窗體的任何直接子控件之間是否存在匹配關(guān)系。LinkButton 是分頁程序的子控件,因此不能運行其服務(wù)器端的代碼。這是否意味著只有窗體的直接子控件才能啟動并處理服務(wù)器事件?當然不是,只要您使用命名容器。 通過使 SqlPager 控件實現(xiàn) INamingContainer 接口,可以將嵌入式鏈接按鈕的實際 ID 從“First”更改為“SqlPager1:First”。當用戶單擊以查看新頁面時,返回事件將 SqlPager1:First 作為目標控件。實際上,運行時用來識別目標控件的算法比上面介紹的要復雜一些。運行時將事件目標控件的名稱看作是用冒號分隔開的字符串。實際上,這種匹配是在窗體的子控件和用冒號分隔開的字符串(如 SqlPager1:First)的第一個標記之間進行的。由于分頁程序是窗體的子控件,因此匹配時會成功,分頁程序獲取單擊事件。假如您認為這種解釋不夠充分或者令人費解,只要下載 SqlPager 控件的源代碼,刪除 INamingContainer 標記接口并進行重新編譯即可。您將看到分頁程序能夠返回,但不能內(nèi)部處理單擊事件。
INamingContainer 接口是一個不具備方法的標記接口,其實現(xiàn)只需在類聲明中指定名稱即可,無需進行任何其他操作。復合控件的另一個重要方面是,它們通常不需要自定義邏輯來進行顯示。復合控件的顯示遵循其組成控件的顯示。生成復合控件時,通常無需覆蓋 Render 方法。 控件的 SqlPager 樹由一個包含兩個單元格的單行表格組成。該表格繼續(xù)了分頁程序的大部分可視設(shè)置,如前景顏色和背景顏色、邊框、字體信息和寬度等。第一個單元格包含導航條,其結(jié)構(gòu)取決于 PagerStyle 屬性的值。假如分頁程序的樣式為 NextPrev,則導航條將由四個 VCR 式的按鈕組成。否則,它將由一個下拉列表組成。private void BuildControlHierarchy(){ // 生成環(huán)境表格(一行,兩個單元格) Table t = new Table(); t.Font.Name = this.Font.Name; t.Font.Size = this.Font.Size; t.BorderStyle = this.BorderStyle; t.BorderWidth = this.BorderWidth; t.BorderColor = this.BorderColor; t.Width = this.Width; t.Height = this.Height; t.BackColor = this.BackColor; t.ForeColor = this.ForeColor; // 生成表格中的行 TableRow row = new TableRow(); t.Rows.Add(row); // 生成帶有導航條的單元格 TableCell cellNavBar = new TableCell(); if (PagerStyle == this.PagerStyle.NextPrev) BuildNextPrevUI(cellNavBar); else BuildNumericPagesUI(cellNavBar); row.Cells.Add(cellNavBar); // 生成帶有頁面索引的單元格 TableCell cellPageDesc = new TableCell(); cellPageDesc.HorizontalAlign = HorizontalAlign.Right; BuildCurrentPage(cellPageDesc); row.Cells.Add(cellPageDesc); // 將表格添加到控件樹 this.Controls.Add(t);} 將各個控件添加到正確的 Controls 集合對于分頁程序的正確顯示極其重要。最外層的表格必須添加到分頁程序的 Controls 集合中。鏈接按鈕和下拉列表必須添加到相應(yīng)表格單元格的 Controls 集合中。下面給出了用來生成鏈接按鈕導航條的代碼。每個按鈕都顯示有一個 Webdings 字符,可以根據(jù)需要禁用,并被綁定到內(nèi)部的 Click 事件處理程序。 private void BuildNextPrevUI(TableCell cell){ bool isValidPage = ((CurrentPageIndex >=0) && (CurrentPageIndex <= TotalPages-1)); bool canMoveBack = (CurrentPageIndex>0); bool canMoveForward = (CurrentPageIndex<TotalPages-1); // 顯示 << 按鈕 LinkButton first = new LinkButton(); first.ID = "First"; first.Click += new EventHandler(first_Click); first.Font.Name = "webdings"; first.Font.Size = FontUnit.Medium; first.ForeColor = ForeColor; first.ToolTip = "第一頁"; first.Text = "7"; first.Enabled = isValidPage && canMoveBack; cell.Controls.Add(first); :} 分頁程序的另一種樣式(在下拉列表中列出數(shù)字頁面)的生成方法如下所示:private void BuildNumericPagesUI(TableCell cell){ // 顯示一個下拉列表 DropDownList pageList = new DropDownList(); pageList.ID = "PageList"; pageList.AutoPostBack = true; pageList.SelectedIndexChanged += new EventHandler(PageList_Click); pageList.Font.Name = this.Font.Name; pageList.Font.Size = Font.Size; pageList.ForeColor = ForeColor; if (TotalPages <=0 CurrentPageIndex == -1) { pageList.Items.Add("No pages"); pageList.Enabled = false; pageList.SelectedIndex = 0; } else // 填充列表 { for(int i=1; i<=TotalPages; i++) { ListItem item = new ListItem(i.ToString(), (i-1).ToString()); pageList.Items.Add(item); } pageList.SelectedIndex = CurrentPageIndex; }}
所有事件處理程序(Click 和 SelectedIndexChanged)最終都會更改當前顯示的頁面。這兩種方法都會調(diào)用一個公用的 private 方法 GoToPage。private void first_Click(object sender, EventArgs e){ GoToPage(0);}private void PageList_Click(object sender, EventArgs e){ DropDownList pageList = (DropDownList) sender; int pageIndex = Convert.ToInt32(pageList.SelectedItem.Value); GoToPage(pageIndex);}private void GoToPage(int pageIndex){ // 預(yù)備事件數(shù)據(jù) PageChangedEventArgs e = new PageChangedEventArgs(); e.OldPageIndex = CurrentPageIndex; e.NewPageIndex = pageIndex; // 更新當前的索引 CurrentPageIndex = pageIndex; // 啟動頁面更改事件 OnPageIndexChanged(e); // 綁定新數(shù)據(jù) DataBind();} 其他導航按鈕的處理程序與 first_Click 的區(qū)別僅在于它們傳遞給 GoToPage 方法的頁碼不同。GoToPage 方法負責處理 PageIndexChanged 事件,并負責啟動數(shù)據(jù)綁定過程。它預(yù)備事件數(shù)據(jù)(舊頁面和新頁面索引)并觸發(fā)事件。GoToPage 被定義為 private,但是可以使用 CurrentPageIndex 屬性通過編程的方式更改顯示的頁面。 public int CurrentPageIndex{ get {return Convert.ToInt32(ViewState["CurrentPageIndex"]);} set {ViewState["CurrentPageIndex"] = value;}} 與表 1 中所列的所有屬性一樣,CurrentPageIndex 屬性的實現(xiàn)方法也相當簡單。它將其內(nèi)容保存到 ViewState 中并從中進行還原。在數(shù)據(jù)綁定過程中,會驗證和使用頁面索引。數(shù)據(jù)綁定過程DataBind 方法是所有 ASP.NET 控件公用的,對于數(shù)據(jù)綁定控件來說,它將觸發(fā)用戶界面的刷新以反映新數(shù)據(jù)。SqlPager 控件根據(jù) SelectCommand 和 ConnectionString 屬性的值,使用此方法啟動數(shù)據(jù)檢索操作。不言而喻,假如這些屬性中的任何一個為空,該過程將終止。同樣,假如合作者控件不存在,數(shù)據(jù)綁定過程將被取消。要查找合作者控件,DataBind 方法使用 Page 類中的 FindControl 函數(shù)。由此可見,合作者控件必須為主窗體的直接子控件。進行分頁顯示的控件不能為任意的 ASP.NET 服務(wù)器控件。它必須為列表控件或基本數(shù)據(jù)列表控件。更一般來說,合作者控件必須具有 DataSource 屬性并實現(xiàn) DataBind 方法??赡苓M行分頁的控件實際上只需要滿足這些要求。Microsoft® .NET Framework 中所有繼續(xù) ListControl 或 BaseDataList 的控件都滿足第一個要求;而所有 Web 控件通過設(shè)計都滿足 DataBind 要求。使用當前的實現(xiàn)方法,無法使用 SqlPager 控件來對 Repeater 進行分頁。Repeater 與合作者控件 DataList 和 DataGrid 不同,不繼續(xù) BaseDataList,也不提供列表控件的功能。下表列出了可以使用 SqlPager 進行分頁的控件。表 2:可以由 SqlPager 控件進行分頁的數(shù)據(jù)綁定控件 控件說明CheckBoxList從 ListControl 派生而來,顯示為復選框列表。 DropDownList從 ListControl 派生而來,顯示為字符串下拉列表。ListBox從 ListControl 派生而來,顯示為字符串可滾動列表。RadioButtonList從 ListControl 派生而來,顯示為單選按鈕列表。DataList從 BaseDataList 派生而來,顯示為模板化數(shù)據(jù)項目列表。DataGrid從 BaseDataList 派生而來,顯示為數(shù)據(jù)項目的表格網(wǎng)格。DataGrid 是唯一一個內(nèi)置有功能強大的分頁引擎的 ASP.NET 控件。 以下代碼說明由 SqlPager 控件實現(xiàn)的數(shù)據(jù)綁定過程。 public override void DataBind(){ // 啟動數(shù)據(jù)綁定事件 base.DataBinding(); // 數(shù)據(jù)綁定后必須重新創(chuàng)建控件 ChildControlsCreated = false; // 確??丶嬖谇覟榱斜砜丶? _controlToPaginate = Page.FindControl(ControlToPaginate); if (_controlToPaginate == null) return; if (!(_controlToPaginate is BaseDataList _controlToPaginate is ListControl)) return; // 確保具有足夠的連接信息并指定查詢 if (ConnectionString == "" SelectCommand == "") return; // 獲取數(shù)據(jù) if (PagingMode == PagingMode.Cached) FetchAllData(); else FetchPageData(); // 將數(shù)據(jù)綁定到合作者控件 BaseDataList baseDataListControl = null; ListControl listControl = null; if (_controlToPaginate is BaseDataList) { baseDataListControl = (BaseDataList) _controlToPaginate; baseDataListControl.DataSource = _dataSource; baseDataListControl.DataBind(); return; } if (_controlToPaginate is ListControl) { listControl = (ListControl) _controlToPaginate; listControl.Items.Clear(); listControl.DataSource = _dataSource; listControl.DataBind(); return; }}
根據(jù) PagingMode 屬性的值調(diào)用不同的獲取例程。在任何情況下,結(jié)果集都綁定到 PagedDataSource 類的實例上。此類提供了一些用來對數(shù)據(jù)進行分頁的功能。非凡是,當整個數(shù)據(jù)集都存儲在緩存中時,該類將自動檢索當前頁面的記錄并返回布爾值,來提供有關(guān)第一頁和最后一頁的信息。稍后將回來介紹此類的內(nèi)部結(jié)構(gòu)。在上述列表中,幫助程序的 PagedDataSource 對象是由 _dataSource 變量表示的。然后,SqlPager 控件經(jīng)過計算得出合作者控件的類型,并將 PagedDataSource 對象的內(nèi)容綁定到合作者控件的 DataSource 屬性。有時,上述的 DataBind 方法還將 ChildControlsCreated 屬性重新設(shè)置為 false。那么,為什么要這樣做呢? 當包含分頁程序的頁面返回時,所有控件都要重新創(chuàng)建;分頁程序也不例外。通常情況下,所有控件及其子控件都是在預(yù)備顯示頁面之前創(chuàng)建的。在每個控件接收到 OnPreRender 通知之前的一瞬間,protected EnsureChildControls 方法將被調(diào)用,這樣,每個控件都可以生成自己的控件樹。此事件發(fā)生后,數(shù)據(jù)綁定過程完成,新數(shù)據(jù)已存儲到緩存中。 但是,當由于單擊分頁程序的一個組成控件而使頁面返回時(即用戶單擊以更改頁面),就會生成分頁程序的控件樹,這時遠未達到顯示階段。非凡是,當處理相關(guān)的服務(wù)器端事件時,就必須生成控件樹,因而是在數(shù)據(jù)綁定開始之前生成控件樹。困難在于,數(shù)據(jù)綁定將修改頁面索引,而這必須反映在用戶界面中。假如不采取某些對策的話,當用戶切換到另一頁時,分頁程序中的頁面索引將不會被刷新。有各種方法可以解決此問題,但重要的是要弄清楚問題及其真正的原因。您可以避免生成控件樹,并在 Render 方法中生成所有輸出。另外,您還可以修改樹中受數(shù)據(jù)綁定更改影響的部分。本文選擇了第三種方法,這種方法需要較少的代碼,而且,不管控件的用戶界面的哪個部分受到數(shù)據(jù)綁定更改的影響,都能夠解決問題。通過將 ChildControlsCreated 屬性設(shè)置為 false,可以使以前創(chuàng)建的任何控件樹無效。這樣,在顯示之前將重新創(chuàng)建控件樹。分頁引擎SqlPager 控件支持兩種檢索數(shù)據(jù)的方法 - 緩存和非緩存。假如采用前者,選擇命令原樣執(zhí)行,整個結(jié)果集將綁定到在內(nèi)部進行分頁的數(shù)據(jù)源對象上。PagedDataSource 對象將自動返回適合特定頁面的記錄。PagedDataSource 類也是在 DataGrid 默認分頁機制背后運行的系統(tǒng)組件。檢索所有記錄但只顯示適合頁面的幾個記錄,這通常不是一種明智的方法。由于 Web 應(yīng)用程序的無狀態(tài)特性,事實上,每次請求頁面時都可能運行大量的查詢。要使操作有效,采用緩存的數(shù)據(jù)檢索方法必須依靠于某種緩存對象,ASP.NET 的 Cache 對象就是一個很好的候選對象。緩存技術(shù)的使用加快了應(yīng)用程序的運行速度,但其提供的數(shù)據(jù)快照不能反映最新的更改。另外,它需要使用 Web 服務(wù)器上的較多內(nèi)存。而且荒謬的是,假如大量的數(shù)據(jù)按會話緩存的話,甚至可能造成很大的問題。Cache 容器對于應(yīng)用程序來說是全局的;假如數(shù)據(jù)按會話存儲在其中,還需生成會話特有的項目名稱。Cache 對象的上面是完全支持過期策略的。換句話說,存儲在緩存中的數(shù)據(jù)在一段時間后可以自動被釋放。以下代碼說明 SqlPager 類中用來獲取數(shù)據(jù)并將其存儲在緩存中的一個 private 方法。private void FetchAllData(){ // 在 ASP.NET Cache 中查找數(shù)據(jù) DataTable data; data = (DataTable) Page.Cache[CacheKeyName]; if (data == null) { // 使用 order-by 信息修改 SelectCommand AdjustSelectCommand(true); // 假如數(shù)據(jù)過期或從未被獲取,則轉(zhuǎn)到數(shù)據(jù)庫 SqlDataAdapter adapter = new SqlDataAdapter(SelectCommand, ConnectionString); data = new DataTable(); adapter.Fill(data); Page.Cache.Insert(CacheKeyName, data, null, DateTime.Now.AddSeconds(CacheDuration), System.Web.Caching.Cache.NoSlidingEXPiration); } // 配置分頁的數(shù)據(jù)源組件 if (_dataSource == null) _dataSource = new PagedDataSource(); _dataSource.DataSource = data.DefaultView; _dataSource.AllowPaging = true; _dataSource.PageSize = ItemsPerPage; TotalPages = _dataSource.PageCount; // 確保頁面索引有效 ValidatePageIndex(); if (CurrentPageIndex == -1) { _dataSource = null; return; } // 選擇要查看的頁面 _dataSource.CurrentPageIndex = CurrentPageIndex;} 控件和請求的緩存項目名稱是唯一的。它包括頁面的 URL 和控件的 ID。在指定的時間(以秒計算)內(nèi),數(shù)據(jù)被綁定到緩存。要使項目過期,必須使用 Cache.Insert 方法。以下較簡單的代碼將項目添加到緩存,但不包括任何過期策略。Page.Cache[CacheKeyName] = data;
PagedDataSource 對象通過其 DataSource 屬性獲取要進行分頁的數(shù)據(jù)。值得注重的是,PagedDataSource 類的 DataSource 屬性只接受 IEnumerable 對象。DataTable 不滿足此要求,這就是為什么采取 DefaultView 屬性的原因。SelectCommand 屬性確定在 SQL Server 數(shù)據(jù)庫上運行的查詢。此字符串最好為 SELECT-FROM-WHERE 形式。不支持 ORDER BY 子句,假如指定了該子句,將被刪除。這正是 AdjustSelectCommand 方法所做的。使用 SortField 屬性可以指定任何排序信息。AdjustSelectCommand 方法本身將根據(jù) SortField 的值添加一個正確的 ORDER BY 子句。這樣做有什么原因嗎?當分頁程序以 NonCached 模式工作時,原始的查詢將被修改以確保只檢索當前頁面的記錄。在 SQL Server 上執(zhí)行的實際查詢文本將采取以下形式。SELECT * FROM (SELECT TOP ItemsPerPage * FROM (SELECT TOP ItemsPerPage*CurrentPageIndex * FROM (SelectCommand) AS t0 ORDER BY SortField ASC) AS t1ORDER BY SortField DESC) AS t2 ORDER BY SortField 該查詢彌補了 SQL Server 2000 中 ROWNUM 子句的缺陷,并且對記錄進行重新排序,使得只有 x 項目的“第 n 個”塊經(jīng)過正確排序后返回。您可以指定基礎(chǔ)查詢,分頁程序?qū)⑺纸鉃槎鄠€較小的頁面。只有適合某個頁面的記錄被返回。正如您看到的那樣,除了查詢命令以外,上述查詢需要處理排序字段。這就是為什么另外添加了 SortField 屬性。此代碼的唯一缺陷是默認情況為升序排序。通過使 ASC/DESC 要害字參數(shù)化,可以使此代碼真的非常完美:private void FetchPageData(){ // 需要經(jīng)過驗證的頁面索引來獲取數(shù)據(jù)。 // 還需要實際的頁數(shù)來驗證頁面索引。 AdjustSelectCommand(false); VirtualRecordCount countInfo = CalculateVirtualRecordCount(); TotalPages = countInfo.PageCount; // 驗證頁碼(確保 CurrentPageIndex 有效或為“-1”) ValidatePageIndex(); if (CurrentPageIndex == -1) return; // 預(yù)備并運行命令 SqlCommand cmd = PrepareCommand(countInfo); if (cmd == null) return; SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataTable data = new DataTable(); adapter.Fill(data); // 配置分頁的數(shù)據(jù)源組件 if (_dataSource == null) _dataSource = new PagedDataSource(); _dataSource.AllowCustomPaging = true; _dataSource.AllowPaging = true; _dataSource.CurrentPageIndex = 0; _dataSource.PageSize = ItemsPerPage; _dataSource.VirtualCount = countInfo.RecordCount; _dataSource.DataSource = data.DefaultView; } 在 NonCached 模式中,PagedDataSource 對象并不提供整個數(shù)據(jù)源,因此不能計算出要進行分頁的總頁數(shù)。進而必須對 AllowCustomPaging 屬性進行標記,并提供數(shù)據(jù)源中的實際記錄數(shù)量。通常,實際數(shù)量是使用 SELECT COUNT(*) 查詢進行檢索的。此模型與 DataGrid 的自定義分頁幾乎相同。此外,PagedDataSource 對象中選擇的當前頁面索引通常為 0,因為實際上已經(jīng)存儲了一頁記錄。SqlPager 控件的實現(xiàn)方法就介紹到這里,下面我們介紹一下它的使用方法。使用 SqlPager 控件假設(shè)存在一個包含 ListBox 控件的示例頁面。要使用分頁程序,請確保 .aspx 頁面正確地注冊了該控件的程序集。 <%@ Register TagPrefix="expo" Namespace="DevCenter" Assembly="SqlPager" %> 控件的標記取決于實際設(shè)置的屬性。以下標記是一個合理的示例:<asp:listbox runat="server" id="ListBox1" Width="300px" Height="168px" DataTextField="companyname" /> <br><expo:SqlPager runat="server" id="SqlPager1" Width="300px" ControlToPaginate="ListBox1" SelectCommand="SELECT customerid, companyname FROM customers" ConnectionString="SERVER=localhost;DATABASE=northwind;UID=..." SortKeyField="companyname" /><br><asp:button runat="server" id="LoadFirst1" Text="加載第一頁" />
除了分頁程序以外,頁面還包含一個列表框和一個按鈕。列表框?qū)@示每個頁面的內(nèi)容;按鈕只用于首次填充列表框。該按鈕具有一個單擊事件處理程序,定義如下。private void LoadFirst1_Click(object sender, EventArgs e) { SqlPager1.CurrentPageIndex = 0; SqlPager1.DataBind(); } 圖 2 顯示操作中的頁面。創(chuàng)建用于 ASP.NET 的分頁程序控件[MSDN](圖二)圖 2:與 ListBox 控件協(xié)同工作的 SqlPager 控件。使用 DataList 控件可以生成一個更有意思的示例。目標是使用分頁程序瀏覽每個 Northwind 職員的個人記錄。該 DataList 如以下列表所示。<asp:datalist runat="server" id="DataList1" Width="300px" Font-Names="Verdana" Font-Size="8pt"><ItemTemplate><table bgcolor="#f0f0f0" style="font-family:verdana;font-size:8pt;"> <tr><td valign="top"> <b><%# DataBinder.Eval(Container.DataItem, "LastName") + ", " + DataBinder.Eval(Container.DataItem, "firstname") %></b></td></tr> <tr><td> <span style="color:blue;"><i> <%# DataBinder.Eval(Container.DataItem, "Title")%></i></span> <p><img style="float:right;" src='image.aspx? id=<%# DataBinder.Eval(Container.DataItem, "employeeid")%>' /> <%# DataBinder.Eval(Container.DataItem, "Notes") %></td></tr></table></ItemTemplate></asp:datalist> 表格的第一行顯示職員的姓名和職務(wù),然后是相片,相片四周是注釋。相片是使用特定的 .aspx 頁面檢索的,返回從數(shù)據(jù)庫中獲取的 JPEG 數(shù)據(jù)。 分頁程序可以放置在頁面中的任何位置。本例中將它放置在合作者 DataList 控件上方并緊挨著合作者控件。創(chuàng)建用于 ASP.NET 的分頁程序控件[MSDN](圖三)圖 3:SqlPager 對 DataList 控件進行分頁 將 SqlPager 控件與 DataGrid 控件一起使用有意義嗎?這要視情況而定。DataGrid 已經(jīng)與一個基于本文中使用的 PagedDataSource 對象的嵌入式分頁引擎一起工作。因此,假如您需要對以表格格式顯示的單個記錄集合進行分頁時,就無需使用 SqlPager。但是,對于重要/復雜的方案,將這兩個控件一起使用并不是一種牽強的想法。例如,假如您要向前一個屏幕快照添加一個 DataGrid 來顯示由職員治理的訂單,則可以在同一格頁面上放置兩個相關(guān)的分頁引擎,一個要對職員進行分頁,另一個用于滾動相關(guān)訂單。小結(jié)不管您要生成哪種類型的應(yīng)用程序(Web 應(yīng)用程序、Microsoft® Windows® 應(yīng)用程序或 Web 服務(wù)),您都很難下載和緩存要顯示的整個數(shù)據(jù)源。有時,測試環(huán)境會使您相信這種解決方案真是太棒了,非??扇?。但是測試環(huán)境也會誤導。數(shù)據(jù)源的大小非常要害,應(yīng)用程序的規(guī)模越大,數(shù)據(jù)源的大小越要害。在 ASP.NET 中,只有 DataGrid 控件具有內(nèi)置的分頁功能。但是,分頁引擎是由相當樣板化的代碼實現(xiàn)的,只要進行少量的處理,就可以進行推廣并用于多個不同的控件。本文介紹的 SqlPager 控件就實現(xiàn)了此目標。它關(guān)注下載數(shù)據(jù),將數(shù)據(jù)分成多個頁面并通過合作者控件顯示。該控件可以檢索并緩存整個數(shù)據(jù)集,或者僅在 SQL Server 中查詢要在選定的頁面中顯示的幾個記錄。我說的是 SQL Server,這是另一個重點。SqlPager 只能用于 SQL Server,不能用于通過 OLE DB 或 ODBC 來檢索數(shù)據(jù)。也不能使用它訪問 Oracle 或 DB2 存檔。 要生成真正的通用 SQL 分頁程序組件,應(yīng)該形成數(shù)據(jù)訪問層,并生成一種能夠使用相應(yīng)的數(shù)據(jù)提供程序創(chuàng)建連接、命令和適配器的工廠類。此外,要注重為各種 SQL 源設(shè)置一個分頁引擎是最糟糕的做法。這里介紹的方法只適用于 SQL Server 7.0 和更高版本。TOP 子句在不同的環(huán)境下具有不同的特性。使用服務(wù)器游標和臨時表格,它可適用于較大范圍的 DBMS 系統(tǒng)。但那將使代碼更為復雜。

作者簡介

Dino Esposito 是一位來自意大利羅馬的培訓教師和顧問。他是 Wintellect(英文)小組的成員,專門研究 ASP.NET 和 ADO.NET,主要在歐洲和美國從事教學和咨詢工作。此外,Dino 還負責治理 Wintellect 的 ADO.NET 課件,并為 MSDN Magazine(英文)的“Cutting Edge”專欄撰寫文章。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
成人勉费视频| 欧美一区二区三区啪啪| 日本中文字幕视频一区| 伊人亚洲福利一区二区三区| 国产视频网站一区二区三区| 欧美理论电影大全| 88av在线视频| 亚洲午夜精品久久久久久app| 亚洲欧美精品午睡沙发| 天堂网免费视频| 国内精品视频免费| 国产成人亚洲综合a∨婷婷| 国产精品电影一区二区三区| 婷婷亚洲五月| 在线中文字幕网站| 亚洲性在线观看| 婷婷视频一区二区三区| 国产精品久久久久久久天堂第1集| 嫩草嫩草嫩草| 久久国产热视频| 狠狠做深爱婷婷综合一区| 宅男在线精品国产免费观看| 91chinesevideo永久地址| 99蜜月精品久久91| 美女的奶胸大爽爽大片| 四虎影视4hu4虎成人| 国产va免费精品观看精品| 免费黄视频网站| 国产精品亚洲第一区在线暖暖韩国| 亚洲欧美国产高清va在线播放| 久久精品视频在线观看免费| 日本一本高清视频| 国产成人综合一区二区三区| 欧美成人做性视频在线播放| 亚州精品国产精品乱码不99按摩| 色三级在线观看| 中文字幕在线播放不卡| 日韩欧美精品免费在线| 国产成人精品999| 韩国一区二区三区四区| 欧美日韩国产综合视频| 波多野结衣在线观看一区二区| 性高湖久久久久久久久aaaaa| 色综合一区二区日本韩国亚洲| 第四色男人最爱上成人网| 97久久超碰福利国产精品…| 最近中文字幕mv免费高清在线| 欧美特黄一级大片| 天堂av在线免费| av老司机在线观看| 国产精品久久亚洲7777| 天天想你在线观看完整版电影免费| 亚洲 欧美 日韩系列| 大片在线观看网站免费收看| 久久影院中文字幕| 欧美激情一区二区三区不卡| gay欧美网站| 黄色录像一级片| 波多野结衣不卡| 色老板视频在线观看| 午夜精品蜜臀一区二区三区免费| 欧美在线观看网站| 亚洲欧美偷拍三级| 男人的天堂日韩| 亚洲欧美日韩精品一区二区| 欧美**vk| 91欧美日韩麻豆精品| 日本成人小视频| 久久久久久九九九九九| 伦理一区二区| 亚洲欧美另类国产| 亚洲日韩成人| 日韩一区二区三| 国产精品一区二区三区av| 四虎影视在线播放| 精品黑人一区二区三区国语馆| 色婷婷一区二区三区四区| 老汉av免费一区二区三区| 久久久久久久极品内射| 欧美精品一区二区三区免费播放| 成人午夜免费在线视频| 欧美午夜aaaaaa免费视频| 亚洲精品国偷拍自产在线观看蜜桃| 欧美日韩美女在线观看| 小日子的在线观看免费第8集| 成人淫片免费视频95视频| 亚洲综合视频一区| 成人黄动漫网站免费| 国产1区二区| 国产精品99久久久久久大便| 一级黄色片大全| 日韩av一区二区在线观看| 免费无码毛片一区二区app| 九九这里只精品视在线99| 九九九热精品免费视频观看网站| 白白色免费视频| 色综合视频网站| 91国产精品91| 在线观看网站免费入口在线观看国内| 最新国产露脸在线观看| 成人午夜激情免费视频| 精品一区在线看| 俺去俺来也在线www色官网| www.夜夜操| 日韩av高清| 日本黄色免费片| 国产精品一区二区av影院萌芽| 亚洲精品成a人ⅴ香蕉片| 日本精品一区在线观看| 亚洲国产你懂的| 国产人妻精品一区二区三区不卡| 日产午夜精品一线二线三线| 成人看片在线| 午夜刺激在线| 国产亚洲综合精品| 亚洲国产精品人人爽夜夜爽| 深田咏美在线x99av| 97久久精品午夜一区二区| 日韩国产专区| 久久综合五月天婷婷伊人| 尹人成人综合网| 亚洲国产日韩美| 成人au免费视频影院| 日本不卡在线| 色婷婷视频在线观看| 精品国产免费久久久久久婷婷| 麻豆成人久久精品二区三区小说| 中国丰满熟妇xxxx性| 91在线精品视频| 无码人妻精品一区二区50| 青草青青国产| 欧美久久在线| 久久久亚洲国产美女国产盗摄| 天天干天天操天天操| 国产69精品久久久久777| 日韩黄色在线| 欧美一级在线看| 成人免费在线观看视频网站| 免费人成黄页网站在线一区二区| 国产又黄又粗又猛又爽的视频| 亚洲欧洲综合另类在线| 一级片一级片一级片| 无码小电影在线观看网站免费| 中文在线天堂库| 精品国产不卡一区二区三区| av污在线观看| 国产一区国产二区国产三区| 久久综合久久鬼| 国产福利电影| 欧美精品在线视频观看| 国产女人18毛片水18精品| 偷偷要91色婷婷| 中文乱码免费一区二区三区下载| 久久久999精品| 日本中文字幕在线免费观看| 亚洲欧洲成视频免费观看| av在线播放天堂| 午夜视频久久久久久| 激情久久久久久久久久久久久久久久| 成视频年人免费看黄网站| 自拍自偷一区二区三区| 三上悠亚在线一区二区| 国产精品一区二区免费在线观看| 毛片aaaaaa| 国产凹凸在线观看一区二区| 国产日韩欧美一区在线| 国产精选一区二区| 好吊一区二区三区| 欧美亚洲一区二区在线观看| 欧美一区二区福利在线| 日本japanese极品少妇| 精品伦理精品一区| 国产又粗又大又长| 91免费看片在线观看| 超薄肉色丝袜足j调教99| 欧美日韩国产中字| 亚洲蜜桃视频| 蜜桃臀av在线| 欧美一级视频在线播放| 国产女主播喷水高潮网红在线| 中文字幕国语官网在线视频| 第一社区sis001原创亚洲| 成人久久18免费网站麻豆| 国产成在线观看免费视频| 91日本在线视频| 欧美成人免费播放| 在线电影福利片| 日本中文字幕在线看| 亚洲国产精品一区二区www| 粉嫩91精品久久久久久久99蜜桃| 视频国产精品| 精品国产午夜肉伦伦影院| www.香蕉视频在线观看| 久久久久久五月天久久久久久久久| 日本福利片高清在线观看| www.8ⅹ8ⅹ羞羞漫画在线看| 97免费高清电视剧观看| 任我爽精品视频在线播放| 午夜亚洲影视| 99精品国产在热久久| 区二区三区在线| 9191国语精品高清在线| 亚洲AV无码乱码国产精品牛牛| 国产福利一区在线| 艳女tv在线观看国产一区| 国产精品久久久久一区二区三区厕所| 精品女同一区二区三区在线播放| av中文在线播放| 久久九九久精品国产免费直播| 在线观看视频污| 午夜精品网站| 久久精品视频在线播放| 中文字幕美女视频| 99reav2| 国产成年人视频网站| 国产精品久久久久久久小唯西川| 欧美日韩综合另类| 美女脱光内衣内裤视频久久网站| 伊人网站在线| 欧美爱爱视频| 日韩第二十一页| 国产一区二区三区直播精品电影| 精品伦理一区二区三区| 国产网站麻豆精品视频| 超碰在线最新网址| 色综合久久天天| 一个人看的www视频在线免费观看| 国产成人精品一区二区| 亚洲 欧美 日韩 国产综合 在线| 国产欧美综合在线观看第十页| 免费看岛国视频在线观看| 视频免费一区二区| 久久精品72免费观看| 91亚洲精品在线观看| 国产影视精品一区二区三区| 一本一道久久a久久综合蜜桃| 99国产精品免费| 亚洲精品视频网上网址在线观看| 欧美日本韩国一区二区| 免费久久精品| 欧美日韩亚洲成人| 国产男男gay体育生网站| 日韩少妇中文字幕| 日本黄色a视频| 日本福利午夜视频在线| 一级国产黄色片| 午夜精品剧场| 国产黄色大片在线观看| 在线视频国内自拍亚洲视频| av网站大全在线观看| 亚洲成人av中文| 日韩精品国内| 久久免费精品| 91免费精品国偷自产在线在线| 天天操夜夜添| 姑娘第5集在线观看免费好剧| 91精品视频在线播放| 久久久久久久久国产精品| 色婷婷av一区二区三区大白胸| 51vv免费精品视频一区二区| 亚洲精品一区二区三区四区五区| 双性尿奴穿贞c带憋尿| 欧美国产精品人人做人人爱| 国产精品视频地址| 香蕉国产精品偷在线观看不卡| 久久av综合网| 95精品视频在线| 99久久久久成人国产免费| 亚洲一区二区免费视频软件合集| 中文字幕1区2区3区| 精品人妻无码一区二区色欲产成人| 伊人久久大香线蕉精品| 亚洲a级在线观看| 1024精品久久久久久久久| 久久久久综合一区二区三区| www.18av.com| 欧美—级高清免费播放| 啊v视频在线| 天天射综合影视| 亚洲视屏在线播放| 日韩一区二区三区视频在线| 国产对白叫床清晰在线播放| 亚洲精选一区二区三区| 日韩高清中文字幕| 亚洲国产精品久久卡一| 91导航在线观看| 黄色软件视频在线观看| 国产日韩综合一区二区性色av| 51精品国产黑色丝袜高跟鞋| 国产精品99久久久久久动医院| 最新电影电视剧在线观看免费观看| 日本一区二区三区四区五区| 久久国内精品一国内精品| 最近日韩中文字幕| av不卡一区| 精品人妻一区二区三区四区不卡| 91激情在线| 91精品麻豆日日躁夜夜躁| 极品尤物av丝袜美腿在线观看| 播放一区二区| 久久亚洲国产成人精品性色| 精品精品国产国产自在线| 亚洲国产精品毛片av不卡在线| 91在线国产福利| 91香蕉视频网| 九九视频免费观看视频精品| 精品成人一区二区三区| 深夜视频在线观看| 成人性生生活性生交12| 亚洲午夜av在线| 免费中文字幕av| 可以看的av网址| 黄色av网站在线观看| 国产成人精品一区| 久久无码人妻一区二区三区| 一区二区三区高清| 成人在线小视频| 欧美一级片一区| 色综合色综合色综合| 美女精品自拍一二三四| 视频这里只有精品| 色噜噜狠狠色综合网图区| 日韩激情啪啪| 中文字幕av资源| 亚洲热在线观看| 日韩xxxx视频| 日本黄色免费片| 日韩8x8x|