ListView + DataPager + LinqDataSource
只是純粹記錄一下使用ListView+DataPager+LinqDataSource的基礎用法
說來慚愧,因為之前所經歷的專案中都沒有使用過「ListView + DataPager + LinqDataSource」
舉凡一般的表格顯示會優先考慮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.
先將分類的下拉選單做出來
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));
}
結果顯示
Step 3.
拉一個LinqDataSource到設計頁面上
資料表的選項要改為「Products」
選擇上圖的「Where」,要加入篩選的條件,要使用頁面上的分類下拉選單控制項來變換資料的內容
資料行選擇「Products」的欄位列出
參數屬性中的預設值不用填入任何值
設定好選項之後,按下「加入」後再按「確定」以完成Where模式的設定
回到設定資料來源畫面後,接下來設定「OrderBy」
設定好排序的欄位與排序的方式
選好後按下確定
完成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);
}
}
最後完成的畫面
資料顯示
分頁
分類選擇
SQL 觀察
是否會像GridView的分頁那樣呢?(將所有的資料一次全部撈回來之後再顯示分頁的資料,很不明智也耗效能)
我們觀察SQL Server Profiler
一開始的初始狀態
詳細的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()函式,然後取得分頁量的資料
我們試著變換分類而且也換頁來看看
詳細的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是可以達成真正的分頁功能,
程式開人員可以擺脫過去要自己處理分頁的許多複雜事件處理。
相關連結:
範例資料庫
Will 保哥
超完美組合:LinqDataSource + ListView + DataPager + jQuery
ListView + DataPager 在不使用 LinqDataSource 時會有問題
RandomHsu (RandomArt.tw)
ListView分頁控制項的使用方法(DataPager)
ListView動態綁定資料來源時的分頁問題
以上
純粹是在寫興趣的,用寫程式、寫文章來抒解工作壓力