ListView + DataPager + LinqDataSource

ListView + DataPager + LinqDataSource
只是純粹記錄一下使用ListView+DataPager+LinqDataSource的基礎用法

 

說來慚愧,因為之前所經歷的專案中都沒有使用過「ListView + DataPager + LinqDataSource」

舉凡一般的表格顯示會優先考慮GridView,而列表顯示會有Repeater, DataList,

雖然知道有ListView可以用,但一直沒有去試著使用。

 

如果遇到分頁呢?如果是用GridView,我是不會去使用GridView的分頁功能,

我都是用ADO.NET以及自定的一個Pager使用者自定控制項,

坦白說,有時候這樣的分頁方式做久了都會覺得煩也覺得有些 stupid …

 

這篇文章就只是純粹記錄一下使用ListView+DataPager+LinqDataSource的基礎用法。

 

需要達到以下的需求:

1. 顯示產品資料,預設顯示所有產品資料。

image

2. 產品分類使用下拉選單,並且下拉選單變換選項時,顯示選定分類的所有產品。

image

3. 分頁功能,產品分類選項改變後,也需要有分頁顯示

image

4. 由分類的某分頁去變換下拉選單選項後,到選定分類產品資料顯示時,如有分頁,需從第一頁開始顯示

目前頁面是在分類「Beverages」(CategoryID = 1),下拉選單選定分類「Grains/Cereals」

image

改變分類後,該分類有分頁顯示,從第一頁開始顯示

image

 

Step 1.

使用Linq to SQL,用 Northwind 建立dbml,這次只有使用兩個Table來做演練,

Categories, Products

image

 

Step 2.

先將分類的下拉選單做出來

image

Category :
<asp:DropDownList ID="ddlCategories" runat="server" AutoPostBack="True">
</asp:DropDownList>

Code Behind

	NorthwindDataContext db = new NorthwindDataContext();

	protected void Page_Load(object sender, EventArgs e)
	{
		if (!Page.IsPostBack)
		{
			DropDownListDataBind();
		}
	}

	private void DropDownListDataBind()
	{
		var categories = db.Categories.OrderBy(c => c.CategoryID);

		List<ListItem> items = new List<ListItem>();
		foreach (var item in categories)
		{
			items.Add(new ListItem(item.CategoryName, item.CategoryID.ToString()));
		}
		this.ddlCategories.Items.AddRange(items.ToArray());
		this.ddlCategories.Items.Insert(0, new ListItem("-- select a Category --", string.Empty));
	}

結果顯示

image

 

Step 3.

拉一個LinqDataSource到設計頁面上

image

 

 

 

 

 

 

 

 

 

 

 

 

資料表的選項要改為「Products」

image

選擇上圖的「Where」,要加入篩選的條件,要使用頁面上的分類下拉選單控制項來變換資料的內容

資料行選擇「Products」的欄位列出

參數屬性中的預設值不用填入任何值

image

 

設定好選項之後,按下「加入」後再按「確定」以完成Where模式的設定

image

回到設定資料來源畫面後,接下來設定「OrderBy」

image

設定好排序的欄位與排序的方式

選好後按下確定

image

完成LinqDataSource的設定

產生的原始碼內容如下,但是要做個小修改

<asp:LinqDataSource ID="LinqDataSource1" runat="server" 
	ContextTypeName="NorthwindDataContext" EntityTypeName="" 
	OrderBy="CategoryID, ProductID" TableName="Products" 
	Where="CategoryID == @CategoryID">
	<WhereParameters>
		<asp:ControlParameter ControlID="ddlCategories" Name="CategoryID" 
			PropertyName="SelectedValue" Type="Int32" />
	</WhereParameters>
</asp:LinqDataSource>

 

 

 

修改後,加上AutoGenerateWhereClause並刪除Where,

<asp:LinqDataSource ID="LinqDataSource1" runat="server" 
	ContextTypeName="NorthwindDataContext" EntityTypeName="" 
	OrderBy="CategoryID, ProductID" TableName="Products" 
	AutoGenerateWhereClause="true">
	<WhereParameters>
		<asp:ControlParameter ControlID="ddlCategories" Name="CategoryID" 
			PropertyName="SelectedValue" Type="Int32" />
	</WhereParameters>
</asp:LinqDataSource>

 

Step 4.

加入 ListView與 DataPager

	<asp:ListView ID="ListView1" runat="server" DataSourceID="LinqDataSource1" 
		onselectedindexchanged="ListView1_SelectedIndexChanged">
		<LayoutTemplate>
				<ul ID="itemPlaceholderContainer" runat="server" style="border-bottom: 1px #bfbfbf solid; padding-bottom: 1px;">
					<li ID="itemPlaceholder" runat="server" />
				</ul>
				<div class="pagination">
					<asp:DataPager ID="DataPager1" runat="server" PageSize="5">
							<Fields>
								<asp:NextPreviousPagerField ButtonCssClass="Previous" ShowNextPageButton="false" PreviousPageText="Previous" /> 
								<asp:NumericPagerField />
								<asp:NextPreviousPagerField ShowPreviousPageButton="false" ButtonCssClass="Next" NextPageText="Next" />
							</Fields>
					</asp:DataPager>
				</div>

		</LayoutTemplate>
		<ItemTemplate>
				<li class="ListContent">
					<span style="font-weight: bold"> CategoryID : <%# Eval("CategoryID") %></span>
					<br />
					ProductId : <%# Eval("ProductID") %>
					<br />
					Name : <%# Eval("ProductName") %>
					<br />
					QuantityPerUnit : <%# Eval("QuantityPerUnit") %>
					<br />
					UnitPrice : <%# Eval("UnitPrice") %>
				</li>
		</ItemTemplate>
	</asp:ListView>

 

Code Behind

處理分頁,要對DataPager的StartRowIndex做判斷設定,

這是因為當有某分類的產品數小於分頁量(PageSize)時並需將StartRowIndex設定為 0 (第一頁)

	protected void ListView1_SelectedIndexChanged(object sender, EventArgs e)
	{
		DataPager dataPager = this.ListView1.FindControl("DataPager1") as DataPager;
		
		int StartRowIndex = dataPager.TotalRowCount < dataPager.PageSize
			 ? 0
			 : dataPager.StartRowIndex;

		dataPager.SetPageProperties(StartRowIndex, dataPager.PageSize, true);
	}

 

Step 5.

接下來處理改變分類後,需要將分頁歸到該分類的第一頁,

這個動作就要在DropDownList的SelectedIndexChanged事件中

Code Behind 1:先增加欄位與屬性用來存放分類的ID

	private int _CategoryID;
	public int CategoryID
	{
		get { return _CategoryID; }
		set { _CategoryID = value; }
	}

Code Behind 2:

	protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
	{
		DataPager dataPager = this.ListView1.FindControl("DataPager1") as DataPager;

		if (string.IsNullOrEmpty(this.ddlCategories.SelectedValue))
		{
			dataPager.SetPageProperties(0, dataPager.PageSize, true);
		}
		else
		{
			if (!this.CategoryID.ToString().Equals(this.ddlCategories.SelectedValue))
			{
				dataPager.SetPageProperties(0, dataPager.PageSize, true);
			}
			this.CategoryID = Convert.ToInt32(this.ddlCategories.SelectedValue);
		}
	}

 

最後完成的畫面

資料顯示

image

分頁

image

分類選擇

image

 

 

 

 

 

SQL 觀察

是否會像GridView的分頁那樣呢?(將所有的資料一次全部撈回來之後再顯示分頁的資料,很不明智也耗效能)

我們觀察SQL Server Profiler

一開始的初始狀態

image

詳細的SQL Statement

exec sp_executesql N'SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], 
[t1].[Discontinued]
FROM (
    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], 
[t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
    FROM [dbo].[Products] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]',N'@p0 int,@p1 int',@p0=0,@p1=5

可以看到由Linq所產生的SQL Statement有使用Row_Number()函式,然後取得分頁量的資料

 

我們試著變換分類而且也換頁來看看

image

詳細的SQL Statement

exec sp_executesql N'SELECT [t1].[ProductID], [t1].[ProductName], [t1].[SupplierID], [t1].[CategoryID], [t1].[QuantityPerUnit], [t1].[UnitPrice], [t1].[UnitsInStock], [t1].[UnitsOnOrder], [t1].[ReorderLevel], 
[t1].[Discontinued]
FROM (
    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], 
[t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
    FROM [dbo].[Products] AS [t0]
    WHERE [t0].[CategoryID] = @p0
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2
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動態綁定資料來源時的分頁問題

 

以上

純粹是在寫興趣的,用寫程式、寫文章來抒解工作壓力