[原創]ExtAspNet秘密花園(十六) — 表格之排序與分頁


排序和分頁是表格必備的兩個重要功能,本章會詳細闡述如何在ExtAspNet中實現這兩個功能。

 

排序

首先來看一個排序的例子,ASPX標簽如下:

   1:   <ext:Grid ID="Grid1" Title="表格" AllowSorting="true" SortColumn="year"
   2:      SortDirection="ASC" Width="750px" AutoHeight="true" runat="server" EnableCheckBoxSelect="True"
   3:      DataKeyNames="Id,Name,AtSchool" EnableRowNumber="True" OnSort="Grid1_Sort">
   4:      <Columns>
   5:          <ext:BoundField Width="100px" ColumnID="name" SortField="Name" DataField="Name" DataFormatString="{0}"
   6:              HeaderText="姓名" />
   7:          <ext:TemplateField Width="60px" SortField="Gender" HeaderText="性別">
   8:              <ItemTemplate>
   9:                  <asp:Label ID="Label2" runat="server" Text='<%# GetGender(Eval("Gender")) %>'></asp:Label>
  10:              </ItemTemplate>
  11:          </ext:TemplateField>
  12:          <ext:BoundField Width="100px" ColumnID="year" SortField="EntranceYear" DataField="EntranceYear" HeaderText="入學年份" />
  13:          <ext:CheckBoxField Width="60px" SortField="AtSchool" RenderAsStaticField="true" DataField="AtSchool"
  14:              HeaderText="是否在校" />
  15:          <ext:HyperLinkField HeaderText="所學專業" DataToolTipField="Major" DataTextField="Major"
  16:              DataTextFormatString="{0}" DataNavigateUrlFields="Major" DataNavigateUrlFormatString="http://gsa.ustc.edu.cn/search?q={0}"
  17:              DataNavigateUrlFieldsEncode="true" Target="_blank" ExpandUnusedSpace="True" />
  18:          <ext:ImageField Width="60px" DataImageUrlField="Group" DataImageUrlFormatString="~/images/16/{0}.png"
  19:              HeaderText="分組"></ext:ImageField>
  20:      </Columns>
  21:  </ext:Grid>

這里面有幾個關鍵點:

  • 表格控件設置排序相關的屬性以及OnSort事件處理函數
    • AllowSorting:是否允許排序。
    • SortColumn:當前排序的列ID,當然也可以不設置此屬性,而是在后台初始化代碼中直接指定默認排序字段。
    • SortDirection:排序方向,ASC(默認值)或者DESC。
  • 對於每一個需要排序的列,設置SortField屬性。

 

來看下后台表格初始化代碼:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          BindGrid();
   6:      }
   7:  }
   8:   
   9:  private void BindGrid()
  10:  {
  11:      GridColumn column = Grid1.FindColumn(Grid1.SortColumn);
  12:      BindGridWithSort(column.SortField, Grid1.SortDirection);
  13:  }
  14:   
  15:  private void BindGridWithSort(string sortField, string sortDirection)
  16:  {
  17:      DataTable table = GetDataTable();
  18:   
  19:      DataView view1 = table.DefaultView;
  20:      view1.Sort = String.Format("{0} {1}", sortField, sortDirection);
  21:   
  22:      Grid1.DataSource = view1;
  23:      Grid1.DataBind();
  24:  }

注意,在調用BindGridWithSort私有函數時,我們通過FindColumn找到默認排序的列,從而找到此列的排序數據字段。

當然,如果沒有設置表格的SortColumn,這里可以直接硬編碼默認的排序字段,比如:

   1:  private void BindGrid()
   2:  {
   3:      BindGridWithSort("EntranceYear", Grid1.SortDirection);
   4:  }

最后是用戶點擊列標題時觸發的排序事件,來看下其事件處理函數:

   1:  protected void Grid1_Sort(object sender, ExtAspNet.GridSortEventArgs e)
   2:  {
   3:      BindGridWithSort(e.SortField, e.SortDirection);
   4:  }

 

是不是非常簡單,最后的顯示效果如下:

image

 

內存分頁

所謂的內存分頁,就是在頁面初始化時將表格數據一次性全部載入,保存在頁面狀態視圖中,從而保證在后續的分頁操作時不用再次訪問數據庫。在數據量少的情況下(一般少於100條數據),這一方式非常划算,因此需要的編碼非常少。下面還是通過一個示例來說明。

先來看下ASPX標簽的結構:

   1:  <ext:Grid ID="Grid1" Title="表格" PageSize="5" ShowBorder="true" ShowHeader="true"
   2:      AutoHeight="true" AllowPaging="true" runat="server" EnableCheckBoxSelect="True"
   3:      Width="800px" DataKeyNames="Id,Name" OnPageIndexChange="Grid1_PageIndexChange"
   4:      EnableRowNumber="True">
   5:      <Columns>
   6:          <ext:BoundField Width="100px" DataField="Name" DataFormatString="{0}" HeaderText="姓名" />
   7:          <ext:TemplateField Width="60px" HeaderText="性別">
   8:              <ItemTemplate>
   9:                  <asp:Label ID="Label2" runat="server" Text='<%# GetGender(Eval("Gender")) %>'></asp:Label>
  10:              </ItemTemplate>
  11:          </ext:TemplateField>
  12:          <ext:BoundField Width="60px" DataField="EntranceYear" HeaderText="入學年份" />
  13:          <ext:CheckBoxField Width="60px" RenderAsStaticField="true" DataField="AtSchool" HeaderText="是否在校" />
  14:          <ext:HyperLinkField HeaderText="所學專業" DataTooltipField="Major" DataTextField="Major"
  15:              DataTextFormatString="{0}" DataNavigateUrlFields="Major" DataNavigateUrlFormatString="http://gsa.ustc.edu.cn/search?q={0}" DataNavigateUrlFieldsEncode="true"
  16:              Target="_blank" ExpandUnusedSpace="True" />
  17:          <ext:ImageField Width="60px" DataImageUrlField="Group" DataImageUrlFormatString="~/images/16/{0}.png"
  18:              HeaderText="分組"></ext:ImageField>
  19:      </Columns>
  20:  </ext:Grid>

這里面有幾個關鍵點:

  • 表格設置屬性AllowPaging=true和PageSize;
  • 表格設置分頁事件處理函數OnPageIndexChange;
  • 各列沒有特殊的屬性設置。

 

看下后台初始化代碼:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          BindGrid();
   6:      }
   7:  }
   8:   
   9:  private void BindGrid()
  10:  {
  11:      DataTable table = GetDataTable();
  12:   
  13:      Grid1.DataSource = table;
  14:      Grid1.DataBind();
  15:  }

可以看到,初始化代碼和不分頁時的代碼一模一樣。

 

再來看下分頁事件處理函數:

   1:  protected void Grid1_PageIndexChange(object sender, ExtAspNet.GridPageEventArgs e)
   2:  {
   3:      Grid1.PageIndex = e.NewPageIndex;
   4:  }

也很簡單,對吧。

 

image

 

其實,如果你之前用過AspNet的GridView的話,這里的代碼和使用GridView的代碼一模一樣。

 

數據庫分頁

在展示大數據時,數據庫分頁是必須的。數據庫分頁時,頁面第一次初始化時只加載表格當前頁的數據,所以每次用戶點擊分頁按鈕時,后台代碼都要進行數據庫查詢並重新綁定當前頁的數據。由於查詢當前頁的數據並綁定表格需要反復調用,通常我們把這一操作提取到一個單獨的函數中。

 

首先看下ASPX標簽的聲明:

   1:  <ext:Grid ID="Grid1" Title="表格" Width="800px" PageSize="5" ShowBorder="true" ShowHeader="true"
   2:      AutoHeight="true" AllowPaging="true" runat="server" EnableCheckBoxSelect="True"
   3:      DataKeyNames="Id,Name" IsDatabasePaging="true" OnPageIndexChange="Grid1_PageIndexChange"
   4:      EnableRowNumber="True">
   5:      <Columns>
   6:          <ext:BoundField Width="100px" DataField="Name" DataFormatString="{0}" HeaderText="姓名" />
   7:          <ext:TemplateField Width="60px" HeaderText="性別">
   8:              <ItemTemplate>
   9:                  <asp:Label ID="Label2" runat="server" Text='<%# GetGender(Eval("Gender")) %>'></asp:Label>
  10:              </ItemTemplate>
  11:          </ext:TemplateField>
  12:          <ext:BoundField Width="60px" DataField="EntranceYear" HeaderText="入學年份" />
  13:          <ext:CheckBoxField Width="60px" RenderAsStaticField="true" DataField="AtSchool" HeaderText="是否在校" />
  14:          <ext:HyperLinkField HeaderText="所學專業" DataTooltipField="Major" DataTextField="Major"
  15:              DataTextFormatString="{0}" DataNavigateUrlFields="Major" DataNavigateUrlFormatString="http://gsa.ustc.edu.cn/search?q={0}" DataNavigateUrlFieldsEncode="true"
  16:              Target="_blank" ExpandUnusedSpace="True" />
  17:          <ext:ImageField Width="60px" DataImageUrlField="Group" DataImageUrlFormatString="~/images/16/{0}.png"
  18:              HeaderText="分組"></ext:ImageField>
  19:      </Columns>
  20:  </ext:Grid>

這里面有幾個關鍵點:

  • 表格設置屬性AllowPaging、IsDatabasePaging、PageSize三個屬性;
  • 表格設置分頁事件處理函數OnPageIndexChange;
  • 各列沒有特殊的屬性設置。

 

看下后台初始化代碼:

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:      if (!IsPostBack)
   4:      {
   5:          BindGrid();
   6:      }
   7:  }
   8:   
   9:  private void BindGrid()
  10:  {
  11:      // 1.設置總項數
  12:      Grid1.RecordCount = GetTotalCount();
  13:   
  14:      // 2.獲取當前分頁數據
  15:      DataTable table = GetPagedDataTable(Grid1.PageIndex, Grid1.PageSize);
  16:   
  17:      // 3.綁定到Grid
  18:      Grid1.DataSource = table;
  19:      Grid1.DataBind();
  20:  }

可以看出初始化表格數據需要如下幾個步驟:

  1. 設置表格的RecordCount屬性,告訴表格總記錄數;
  2. 根據表格的PageIndex(默認是0)和PageSize屬性,從數據庫查詢本頁的數據;
  3. 將查詢到的本頁數據綁定到表格。

 

由此可以看出,表格必須知道如下四種數據后,才能正確顯示:

 

    • 當前是第幾頁(PageIndex);
    • 總共有多少條數據(RecordCount);
    • 每頁顯示多少條數據(PageSize);
    • 當前頁的數據是什么(DataSource)。

 

再來看下分頁事件處理函數:

   1:  protected void Grid1_PageIndexChange(object sender, ExtAspNet.GridPageEventArgs e)
   2:  {
   3:      Grid1.PageIndex = e.NewPageIndex;
   4:   
   5:      BindGrid();
   6:  }

首先告訴表格接下來應該顯示哪一頁,然后重新查詢數據庫並綁定當前頁的數據。

 

界面顯示效果和內存分頁時一樣,就不再截圖。

 

 

為什么說內存分頁在大數據時性能差?

其實原因前面已經提到了,主要是因為內存分頁時會把所有表格數據保存到頁面的狀態視圖中(ViewState),導致頁面大小迅速增加,從而增加網絡下載上載的時間,並且減慢了頁面的渲染速度。

 

雖然ExtAspNet放棄了在ViewState中保存數據,從而可以在Ajax的環境中減少網絡的數據傳輸量,但是內存分頁時所有的表格數據還是要保存下來,供下次分頁時使用。

拿本篇文章中的內存分頁示例,在用戶點擊下一頁時,通過FireBug可以看到這次HTTP Post請求:

image

 

其中X_STATE就是ExtAspNet保存控件狀態的地方,把全部X_STATE的內容拷貝下來,並執行如下JavaScript代碼:

   1:  var xstate = JSON.parse(Base64.decode('eyJHcmlk...FtdXX19'));
   2:  var values = xstate.Grid1.X_Rows.Values;
   3:  values.length + '\r\n' + JSON.stringify(values);

可以看到如下的執行結果:

image

由此可見,全部的11條數據在每次頁面回發時都會作為HTTP Post的參數上傳到服務器,從而在大數據量的情況下導致頁面性能急劇下降。

 

 

小結

排序和分頁是表格的最基本操作,也是每個程序員都應該熟練掌握的知識。特別是處理大量數據(一般大於100條)一定要使用數據庫分頁,否則頁面性能會非常差。下一篇文章我們會討論ExtAspNet對表格的擴展列,包括序號列、選擇框列、行擴展列、模擬樹列以及彈出窗體列。

 

注:《ExtAspNet秘密花園》系列文章由三生石上原創,博客園首發,轉載請注明出處。文章目錄 官方論壇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM