功能特色
- **完整分頁導航**:首頁、上一頁、頁碼、下一頁、尾頁 (LinkButton 動態產生)。
- **鍵盤上下鍵選取列**:`↑`/`↓` 切換焦點列,按 `Enter` 或點擊確認選取。
- **選取列高亮**:紅色背景標示目前選取列。
- **修改按鈕同步**:將選取列資料填入 TextBox 供編輯。
前端 .aspx 關鍵標記
<asp:GridView ID="gvData" runat="server" AutoGenerateColumns="False"
AllowPaging="True" PageSize="5"
OnPageIndexChanging="gvData_PageIndexChanging"
OnRowCreated="gvData_RowCreated"
OnRowDataBound="gvData_RowDataBound">
<Columns>
<asp:BoundField DataField="id" HeaderText="編號" />
<asp:BoundField DataField="name" HeaderText="名稱" />
<!-- 其他欄位 -->
</Columns>
<PagerSettings Mode="NumericFirstLast" /> <!-- 內建頁碼,我們將在 RowCreated 取代 -->
</asp:GridView>
<asp:TextBox ID="NUM" runat="server" Visible="False" /> <!-- 儲存選取列索引 -->
<asp:TextBox ID="tbValue" runat="server" /> <!-- 修改時填入的值 -->
<asp:Button ID="btnUpd" runat="server" Text="修改" OnClick="btnUpd_Click" />
JavaScript 鍵盤導航與高亮 (置於 <head>)
<script type="text/javascript">
var currentRowId = 0;
var originalBgColor = "";
// 鍵盤事件:GridView 行獲得焦點時觸發
function SelectRow(ev, gridId) {
var e = window.event || ev;
var key = e.which || e.keyCode;
if (key == 40) MarkRow(currentRowId + 1, gridId); // Down
if (key == 38) MarkRow(currentRowId - 1, gridId); // Up
document.getElementById("NUM").value = currentRowId;
}
// 高亮指定列
function MarkRow(rowId, gridId) {
var grid = document.getElementById(gridId);
if (!grid || !document.getElementById(gridId + rowId)) return;
if (rowId >= grid.rows.length) return;
// 恢復前一列顏色
if (document.getElementById(gridId + currentRowId))
document.getElementById(gridId + currentRowId).style.backgroundColor = originalBgColor;
currentRowId = rowId;
var targetRow = document.getElementById(gridId + rowId);
originalBgColor = targetRow.style.backgroundColor;
targetRow.style.backgroundColor = 'red';
targetRow.cells[0].focus(); // 移動焦點以接收鍵盤事件
document.getElementById("NUM").value = currentRowId;
}
</script>
<style>
.hidden { display: none; }
</style>
後端 .aspx.cs 核心邏輯
1. 資料繫結
SqlConnection con = new SqlConnection("Server=...;Database=...;User ID=...;Pwd=...;");
private void GetBind()
{
string sql = "SELECT * FROM im01";
SqlDataAdapter da = new SqlDataAdapter(sql, con);
DataSet ds = new DataSet();
da.Fill(ds);
gvData.DataSource = ds;
gvData.DataBind();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) GetBind();
}
2. RowCreated:動態產生分頁導航按鈕
int _rowIndex = 0; // 用於賦予每列唯一 ID
protected void gvData_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Pager)
{
// 建立四個 LinkButton
var btnFirst = NewPageButton("第一頁", "first");
var btnPrev = NewPageButton("上一頁", "previous");
var btnNext = NewPageButton("下一頁", "next");
var btnLast = NewPageButton("尾頁", "last");
// 插入至 Pager Table 首尾
var pagerTable = e.Row.Controls[0].Controls[0] as Table;
var firstCell = pagerTable.Rows[0].Cells[0];
var lastCell = pagerTable.Rows[0].Cells[pagerTable.Rows[0].Cells.Count - 1];
firstCell.Controls.AddAt(0, btnFirst);
firstCell.Controls.AddAt(1, btnPrev);
lastCell.Controls.Add(btnNext);
lastCell.Controls.Add(btnLast);
}
}
private LinkButton NewPageButton(string text, string commandName)
{
var btn = new LinkButton
{
Text = " " + text + " ",
CommandName = commandName,
ForeColor = System.Drawing.Color.Blue
};
btn.Click += PageButtonClick;
return btn;
}
3. RowDataBound:賦予每列 ID、綁定鍵盤/點擊事件
protected void gvData_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["style"] = "cursor:pointer;";
}
string gridId = "gvData";
e.Row.Attributes["id"] = gridId + _rowIndex;
e.Row.Attributes["onkeydown"] = $"SelectRow(event,'{gridId}');";
e.Row.Attributes["onclick"] = $"MarkRow({_rowIndex},'{gridId}');";
e.Row.Attributes["tabindex"] = "0"; // 使 tr 可獲焦點
_rowIndex++;
}
4. 分頁按鈕點擊事件
protected void PageButtonClick(object sender, EventArgs e)
{
var btn = (LinkButton)sender;
switch (btn.CommandName)
{
case "first": gvData.PageIndex = 0; break;
case "previous": if (gvData.PageIndex > 0) gvData.PageIndex--; break;
case "next": if (gvData.PageIndex < gvData.PageCount - 1) gvData.PageIndex++; break;
case "last": gvData.PageIndex = gvData.PageCount - 1; break;
}
GetBind();
}
5. 修改按鈕:取得選取列資料
protected void btnUpd_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(NUM.Text) || NUM.Text == "0")
{
ClientScript.RegisterStartupScript(GetType(), "alert", "alert('請先選取一列資料!');", true);
return;
}
int index = int.Parse(NUM.Text) - 1; // JS 索引從 0 開始
if (index >= 0 && index < gvData.Rows.Count)
{
tbValue.Text = gvData.Rows[index].Cells[1].Text; // 假設第 2 欄為名稱
}
}
效果展示

進階優化建議
- ViewState 儲存 `_rowIndex`:分頁後 `_rowIndex` 歸零,需在 `PageIndexChanging` 重置或使用 `ViewState["RowIndex"]` 保持。
- 使用 `DataKeyNames` 取主鍵**:`gvData.DataKeyNames = "id";` 修改時 `gvData.DataKeys[index].Value` 更可靠。
- CSS 類別替代內嵌 Style**:`.selected-row { background:#f00; color:#fff; }` JS 切換 `classList.toggle`。
- 無障礙 (a11y)**:`
`、`aria-selected`、`role="grid"`。
- 大量資料改用 `ObjectDataSource` + 自訂分頁 SQL (ROW_NUMBER/OFFSET FETCH)**,避免全表撈取。
- 上一篇文章: .NET 多執行緒程式設計實戰總結:前景/背景執行緒、同步鎖、委派本質
- 下一篇文章: ASP.NET 動態載入 CSS 實現多介面/換膚:兩種實作方案
Copyright © 程式碼之家 All Rights Reserved
|