舉凡一般的表格顯示會優先考慮GridView,而列表顯示會有Repeater, DataList,
雖然知道有ListView可以用,但一直沒有去試著使用。
如果遇到分頁呢?如果是用GridView,我是不會去使用GridView的分頁功能,
我都是用ADO.NET以及自定的一個Pager使用者自定控制項,
坦白說,有時候這樣的分頁方式做久了都會覺得煩也覺得有些 stupid …
這篇文章就只是純粹記錄一下使用ListView+DataPager+LinqDataSource的基礎用法。
需要達到以下的需求:
1. 顯示產品資料,預設顯示所有產品資料。
2. 產品分類使用下拉選單,並且下拉選單變換選項時,顯示選定分類的所有產品。
3. 分頁功能,產品分類選項改變後,也需要有分頁顯示
4. 由分類的某分頁去變換下拉選單選項後,到選定分類產品資料顯示時,如有分頁,需從第一頁開始顯示
目前頁面是在分類「Beverages」(CategoryID = 1),下拉選單選定分類「Grains/Cereals」
改變分類後,該分類有分頁顯示,從第一頁開始顯示
Step 1.
使用Linq to SQL,用 Northwind 建立dbml,這次只有使用兩個Table來做演練,
Categories, Products
Step 2.
先將分類的下拉選單做出來
1: Category :
2: <asp:DropDownList ID="ddlCategories" runat="server" AutoPostBack="True">
3: </asp:DropDownList>
Code Behind
1: NorthwindDataContext db = new NorthwindDataContext();
2:
3: protected void Page_Load(object sender, EventArgs e)
4: {
5: if (!Page.IsPostBack)
6: {
7: DropDownListDataBind();
8: }
9: }
10:
11: private void DropDownListDataBind()
12: {
13: var categories = db.Categories.OrderBy(c => c.CategoryID);
14:
15: List<ListItem> items = new List<ListItem>();
16: foreach (var item in categories)
17: {
18: items.Add(new ListItem(item.CategoryName, item.CategoryID.ToString()));
19: }
20: this.ddlCategories.Items.AddRange(items.ToArray());
21: this.ddlCategories.Items.Insert(0, new ListItem("-- select a Category --", string.Empty));
22: }
Step 3.
拉一個LinqDataSource到設計頁面上
資料表的選項要改為「Products」
選擇上圖的「Where」,要加入篩選的條件,要使用頁面上的分類下拉選單控制項來變換資料的內容
資料行選擇「Products」的欄位列出
參數屬性中的預設值不用填入任何值
設定好選項之後,按下「加入」後再按「確定」以完成Where模式的設定
回到設定資料來源畫面後,接下來設定「OrderBy」
設定好排序的欄位與排序的方式
選好後按下確定
完成LinqDataSource的設定
產生的原始碼內容如下,但是要做個小修改
1: <asp:LinqDataSource ID="LinqDataSource1" runat="server"
2: ContextTypeName="NorthwindDataContext" EntityTypeName=""
3: OrderBy="CategoryID, ProductID" TableName="Products"
4: Where="CategoryID == @CategoryID">
5: <WhereParameters>
6: <asp:ControlParameter ControlID="ddlCategories" Name="CategoryID"
7: PropertyName="SelectedValue" Type="Int32" />
8: </WhereParameters>
9: </asp:LinqDataSource>
修改後,加上AutoGenerateWhereClause並刪除Where,
1: <asp:LinqDataSource ID="LinqDataSource1" runat="server"
2: ContextTypeName="NorthwindDataContext" EntityTypeName=""
3: OrderBy="CategoryID, ProductID" TableName="Products"
4: AutoGenerateWhereClause="true">
5: <WhereParameters>
6: <asp:ControlParameter ControlID="ddlCategories" Name="CategoryID"
7: PropertyName="SelectedValue" Type="Int32" />
8: </WhereParameters>
9: </asp:LinqDataSource>
Step 4.
加入 ListView與 DataPager
1: <asp:ListView ID="ListView1" runat="server" DataSourceID="LinqDataSource1"
2: onselectedindexchanged="ListView1_SelectedIndexChanged">
3: <LayoutTemplate>
4: <ul ID="itemPlaceholderContainer" runat="server" style="border-bottom: 1px #bfbfbf solid; padding-bottom: 1px;">
5: <li ID="itemPlaceholder" runat="server" />
6: </ul>
7: <div class="pagination">
8: <asp:DataPager ID="DataPager1" runat="server" PageSize="5">
9: <Fields>
10: <asp:NextPreviousPagerField ButtonCssClass="Previous" ShowNextPageButton="false" PreviousPageText="Previous" />
11: <asp:NumericPagerField />
12: <asp:NextPreviousPagerField ShowPreviousPageButton="false" ButtonCssClass="Next" NextPageText="Next" />
13: </Fields>
14: </asp:DataPager>
15: </div>
16:
17: </LayoutTemplate>
18: <ItemTemplate>
19: <li class="ListContent">
20: <span style="font-weight: bold"> CategoryID : <%# Eval("CategoryID") %></span>
21: <br />
22: ProductId : <%# Eval("ProductID") %>
23: <br />
24: Name : <%# Eval("ProductName") %>
25: <br />
26: QuantityPerUnit : <%# Eval("QuantityPerUnit") %>
27: <br />
28: UnitPrice : <%# Eval("UnitPrice") %>
29: </li>
30: </ItemTemplate>
31: </asp:ListView>
Code Behind
處理分頁,要對DataPager的StartRowIndex做判斷設定,
這是因為當有某分類的產品數小於分頁量(PageSize)時並需將StartRowIndex設定為 0 (第一頁)
1: protected void ListView1_SelectedIndexChanged(object sender, EventArgs e)
2: {
3: DataPager dataPager = this.ListView1.FindControl("DataPager1") as DataPager;
4:
5: int StartRowIndex = dataPager.TotalRowCount < dataPager.PageSize
6: ? 0
7: : dataPager.StartRowIndex;
8:
9: dataPager.SetPageProperties(StartRowIndex, dataPager.PageSize, true);
10: }
Step 5.
接下來處理改變分類後,需要將分頁歸到該分類的第一頁,
這個動作就要在DropDownList的SelectedIndexChanged事件中
Code Behind 1:先增加欄位與屬性用來存放分類的ID
1: private int _CategoryID;
2: public int CategoryID
3: {
4: get { return _CategoryID; }
5: set { _CategoryID = value; }
6: }
Code Behind 2:
1: protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
2: {
3: DataPager dataPager = this.ListView1.FindControl("DataPager1") as DataPager;
4:
5: if (string.IsNullOrEmpty(this.ddlCategories.SelectedValue))
6: {
7: dataPager.SetPageProperties(0, dataPager.PageSize, true);
8: }
9: else
10: {
11: if (!this.CategoryID.ToString().Equals(this.ddlCategories.SelectedValue))
12: {
13: dataPager.SetPageProperties(0, dataPager.PageSize, true);
14: }
15: this.CategoryID = Convert.ToInt32(this.ddlCategories.SelectedValue);
16: }
17: }
最後完成的畫面
資料顯示
分頁
分類選擇
SQL 觀察
是否會像GridView的分頁那樣呢?(將所有的資料一次全部撈回來之後再顯示分頁的資料,很不明智也耗效能)
我們觀察SQL Server Profiler
一開始的初始狀態
詳細的SQL Statement
1: exec sp_executesql N'SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel],
2: [t1].[Discontinued]
3: FROM (
4: SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ProductID]) AS [ROW_NUMBER], [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock],
5: [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
6: FROM [dbo].[Products] AS [t0]
7: ) AS [t1]
8: WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
9: ORDER BY [t1].[ROW_NUMBER]',N'@p0 int,@p1 int',@p0=0,@p1=5
可以看到由Linq所產生的SQL Statement有使用Row_Number()函式,然後取得分頁量的資料
我們試著變換分類而且也換頁來看看
詳細的SQL Statement
1: exec sp_executesql N'SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel],
2: [t1].[Discontinued]
3: FROM (
4: SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ProductID]) AS [ROW_NUMBER], [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock],
5: [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
6: FROM [dbo].[Products] AS [t0]
7: WHERE [t0].[CategoryID] = @p0
8: ) AS [t1]
9: WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2
10: ORDER BY [t1].[ROW_NUMBER]',N'@p0 int,@p1 int,@p2 int',@p0=1,@p1=10,@p2=5
分類編號 @p0 = 1
分頁起始RowInde @p1=10
分頁量 @p2=5
由以上的觀察可以看出,ListView + DataPager + LinqDataSource是可以達成真正的分頁功能,
程式開人員可以擺脫過去要自己處理分頁的許多複雜事件處理。
相關連結:
範例資料庫
下載 Northwind 和 pubs 範例資料庫
Will 保哥
超完美組合:LinqDataSource + ListView + DataPager + jQuery
ListView + DataPager 在不使用 LinqDataSource 時會有問題
RandomHsu (RandomArt.tw)
ListView分頁控制項的使用方法(DataPager)
ListView動態綁定資料來源時的分頁問題以上
沒有留言:
張貼留言