本文提供一個完整的 ASP.NET Web Forms 搜尋分頁範例,包含前端介面(關鍵字輸入、分頁按鈕)、後端邏輯(參數化 SQL 分頁查詢、總筆數計算、ViewState 管理頁碼狀態),採用 `TOP ... NOT IN` 分頁語法,相容 SQL Server 2000+。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="分頁.aspx.cs" Inherits="分頁練習.分頁" %>
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title>搜尋分頁範例</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr><td>
<asp:TextBox ID="txtKey" runat="server" placeholder="輸入關鍵字" />
<asp:ImageButton ID="btnQuery" runat="server" OnClick="btnQuery_Click"
ImageUrl="~/images/0.jpg" Width="20" Height="20" />
<asp:Label ID="Label1" runat="server" />
</td></tr>
<tr><td>
<div id="divResult" runat="server"></div>
</td></tr>
<tr><td>
<asp:LinkButton ID="btnFirst" runat="server" OnClick="btnFirst_Click">第一頁</asp:LinkButton>
<asp:LinkButton ID="btnBefore" runat="server" OnClick="btnBefore_Click">上一頁</asp:LinkButton>
<asp:LinkButton ID="btnNext" runat="server" OnClick="btnNext_Click">下一頁</asp:LinkButton>
<asp:LinkButton ID="btnLast" runat="server" OnClick="btnLast_Click">最後一頁</asp:LinkButton>
</td></tr>
</table>
</div>
</form>
</body>
</html>
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace 分頁練習
{
public partial class 分頁 : Page
{
private const int PageSize = 3; // 每頁筆數
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["pageindex"] = 1; // 目前頁碼(1-based)
LoadData();
CountTotal();
}
}
// 載入當頁資料並渲染 HTML 表格
private void LoadData()
{
string connStr = "Data Source=PC-DLL;Initial Catalog=News;Persist Security Info=True;User Id=sa;Password=linlin";
int pageIndex = Convert.ToInt32(ViewState["pageindex"]);
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = conn.CreateCommand())
{
// 參數化分頁查詢:TOP @PageSize + NOT IN (TOP @Offset)
cmd.CommandText = @"
SELECT TOP (@PageSize) *
FROM T_News
WHERE (NewsTitle LIKE @Key OR NewsContent LIKE @Key)
AND Id NOT IN (
SELECT TOP ((@PageIndex - 1) * @PageSize) Id
FROM T_News
WHERE NewsTitle LIKE @Key OR NewsContent LIKE @Key
ORDER BY Id
)
ORDER BY Id";
cmd.Parameters.AddWithValue("@Key", "%" + txtKey.Text + "%");
cmd.Parameters.AddWithValue("@PageSize", PageSize);
cmd.Parameters.AddWithValue("@PageIndex", pageIndex);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
adapter.Fill(dt);
// 動態產生 HTML 表格
StringBuilder sb = new StringBuilder();
sb.Append("<table border='1' cellpadding='5'><tr><th>標題</th><th>內容</th><th>建立時間</th></tr>");
foreach (DataRow row in dt.Rows)
{
sb.Append("<tr>");
sb.Append("<td>" + Server.HtmlEncode(row["NewsTitle"].ToString()) + "</td>");
sb.Append("<td>" + Server.HtmlEncode(row["NewsContent"].ToString()) + "</td>");
sb.Append("<td>" + row["CreateTime"] + "</td>");
sb.Append("</tr>");
}
sb.Append("</table>");
divResult.InnerHtml = sb.ToString();
}
}
// 計算總筆數與總頁數
private void CountTotal()
{
string connStr = "Data Source=PC-DLL;Initial Catalog=News;Persist Security Info=True;User Id=sa;Password=linlin";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT COUNT(*) FROM T_News WHERE NewsTitle LIKE @Key OR NewsContent LIKE @Key";
cmd.Parameters.AddWithValue("@Key", "%" + txtKey.Text + "%");
conn.Open();
int total = Convert.ToInt32(cmd.ExecuteScalar());
int lastPage = (total % PageSize == 0) ? total / PageSize : total / PageSize + 1;
ViewState["pagelastindex"] = lastPage; // 總頁數
}
}
// 分頁按鈕事件
protected void btnFirst_Click(object sender, EventArgs e)
{
ViewState["pageindex"] = 1;
LoadData();
}
protected void btnBefore_Click(object sender, EventArgs e)
{
int idx = Convert.ToInt32(ViewState["pageindex"]);
if (idx > 1)
{
ViewState["pageindex"] = idx - 1;
LoadData();
}
}
protected void btnNext_Click(object sender, EventArgs e)
{
int idx = Convert.ToInt32(ViewState["pageindex"]);
int last = Convert.ToInt32(ViewState["pagelastindex"]);
if (idx < last)
{
ViewState["pageindex"] = idx + 1;
LoadData();
}
}
protected void btnLast_Click(object sender, EventArgs e)
{
ViewState["pageindex"] = ViewState["pagelastindex"];
LoadData();
}
protected void btnQuery_Click(object sender, ImageClickEventArgs e)
{
ViewState["pageindex"] = 1; // 搜尋重置第一頁
CountTotal();
LoadData();
}
}
}
| 技術點 | 實作細節 |
|---|---|
| 參數化查詢 | 所有使用者輸入(`txtKey.Text`)透過 `SqlParameter` 傳入,**完全防止 SQL Injection** |
| 分頁 SQL | `SELECT TOP @PageSize ... WHERE Id NOT IN (SELECT TOP ((@PageIndex-1)*@PageSize) ...)` 相容 SQL Server 2000+,無需 `ROW_NUMBER()` |
| 狀態管理 | `ViewState["pageindex"]` 儲存目前頁碼(1-based),`ViewState["pagelastindex"]` 儲存總頁數 |
| 搜尋重置 | 點擊查詢按鈕時,`pageindex` 重設為 1,並重新計算總頁數 |
| HTML 編碼輸出 | `Server.HtmlEncode()` 防止資料內含 HTML 標籤導致 XSS 或版面錯亂 |
| 資源釋放 | `using` 區塊確保 `SqlConnection`、`SqlCommand`、`SqlDataAdapter` 正確 Dispose |
此範例展示了 ASP.NET Web Forms 中**搜尋 + 分頁**的核心實作模式:參數化 SQL 保護安全、`ViewState` 管理分頁狀態、`TOP NOT IN` 相容性分頁語法、手動 HTML 渲染。理解此基礎模式,即可擴充至 GridView、ListView、Repeater 等進階控制項應用。