首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Repeater ItemCommand 事件取得行內控制項值完整教學

     編輯:ASP.NET 基礎

Repeater 控制項核心優勢

Repeater 是 ASP.NET 最輕量、彈性最高的資料繫結控制項:

  • 無預設 HTML 輸出,完全由開發者掌控樣板
  • 支援巢狀繫結、複雜版面配置
  • ItemCommand 事件統一處理列內按鈕/連結指令
  • 效能優於 GridView/DataList (無 ViewState 膨脹)

核心技巧:e.Item.FindControl("控制項ID")

在 ItemCommand 事件中,透過 e.Item (當前觸發事件的 RepeaterItem) 呼叫 FindControl 取得該列內的任意控制項實例,進而讀取/設定其屬性值。

完整範例:含 TextBox 輸入與 Button 更新

前端頁面 (RepeaterDemo.aspx)

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RepeaterDemo.aspx.cs" Inherits="Demo.RepeaterDemo" %>
<!DOCTYPE html>
<html>
<head>
    <title>Repeater ItemCommand 示範</title>
    <style>
        .repeater-table { width: 100%; border-collapse: collapse; }
        .repeater-table th, .repeater-table td { border: 1px solid #ddd; padding: 8px; }
        .repeater-table th { background: #f5f5f5; }
        .txt-num { width: 60px; text-align: center; }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <h3>產品庫存數量調整</h3>
        <table class="repeater-table">
            <thead>
                <tr><th>產品名稱</th><th>目前庫存</th><th>調整數量</th><th>操作</th></tr>
            </thead>
            <tbody>
                <asp:Repeater ID="rptProducts" runat="server" OnItemCommand="rptProducts_ItemCommand">
                    <ItemTemplate>
                        <tr>
                            <td><%# Eval("ProductName") %></td>
                            <td><%# Eval("StockQty") %></td>
                            <td>
                                <asp:TextBox ID="txtAdjustQty" runat="server" CssClass="txt-num" Text="0" />
                            </td>
                            <td>
                                <asp:Button ID="btnUpdate" runat="server" Text="更新" 
                                    CommandName="update" 
                                    CommandArgument='<%# Eval("ProductID") %>' 
                                    CssClass="btn btn-primary" />
                            </td>
                        </tr>
                    </ItemTemplate>
                </asp:Repeater>
            </tbody>
        </table>
        <asp:Label ID="lblMsg" runat="server" ForeColor="Green" />
    </form>
</body>
</html>

後端程式碼 (RepeaterDemo.aspx.cs)

using System;
using System.Data;
using System.Web.UI.WebControls;

namespace Demo
{
    public partial class RepeaterDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack) BindRepeater();
        }

        private void BindRepeater()
        {
            // 模擬資料來源
            DataTable dt = new DataTable();
            dt.Columns.Add("ProductID", typeof(int));
            dt.Columns.Add("ProductName", typeof(string));
            dt.Columns.Add("StockQty", typeof(int));
            
            dt.Rows.Add(1, "筆記型電腦", 50);
            dt.Rows.Add(2, "無線滑鼠", 200);
            dt.Rows.Add(3, "機械鍵盤", 80);
            dt.Rows.Add(4, "27吋螢幕", 30);
            
            rptProducts.DataSource = dt;
            rptProducts.DataBind();
        }

        protected void rptProducts_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            if (e.CommandName == "update")
            {
                // 1. 取得 CommandArgument (主鍵 ID)
                int productId = Convert.ToInt32(e.CommandArgument);
                
                // 2. 關鍵:透過 e.Item.FindControl 取得該列內的 TextBox
                TextBox txtAdjustQty = e.Item.FindControl("txtAdjustQty") as TextBox;
                
                if (txtAdjustQty != null)
                {
                    // 3. 讀取使用者輸入值
                    if (int.TryParse(txtAdjustQty.Text.Trim(), out int adjustQty))
                    {
                        // 4. 執行業務邏輯 (此處僅示範)
                        // bool success = ProductService.UpdateStock(productId, adjustQty);
                        bool success = true; // 模擬成功
                        
                        if (success)
                        {
                            lblMsg.Text = $"✅ 產品 ID {productId} 庫存已調整 {adjustQty} 件";
                            BindRepeater(); // 重新繫結顯示最新狀態
                        }
                        else
                        {
                            lblMsg.Text = "❌ 更新失敗,請稍後再試";
                        }
                    }
                    else
                    {
                        lblMsg.Text = "❌ 請輸入有效的數字";
                    }
                }
            }
        }
    }
}

進階應用場景

1. 取得多種控制項值 (DropDownList, CheckBox, HiddenField, Label)

protected void rpt_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    // DropDownList
    DropDownList ddlStatus = e.Item.FindControl("ddlStatus") as DropDownList;
    string status = ddlStatus?.SelectedValue;

    // CheckBox
    CheckBox chkActive = e.Item.FindControl("chkActive") as CheckBox;
    bool isActive = chkActive?.Checked ?? false;

    // HiddenField (常用於儲存不顯示的主鍵/版本號)
    HiddenField hfVersion = e.Item.FindControl("hfVersion") as HiddenField;
    int version = Convert.ToInt32(hfVersion?.Value ?? "0");

    // Label (唯讀顯示值)
    Label lblCreatedDate = e.Item.FindControl("lblCreatedDate") as Label;
    DateTime createdDate = DateTime.Parse(lblCreatedDate?.Text ?? DateTime.Now.ToString());
}

2. 巢狀 Repeater 取得父層/子層控制項

<asp:Repeater ID="rptCategory" runat="server" OnItemCommand="rptCategory_ItemCommand">
    <ItemTemplate>
        <h4><%# Eval("CategoryName") %></h4>
        <asp:Repeater ID="rptProducts" runat="server" DataSource='<%# Eval("Products") %>' OnItemCommand="rptProducts_ItemCommand">
            <ItemTemplate>
                <asp:TextBox ID="txtQty" runat="server" />
                <asp:Button ID="btnAdd" runat="server" CommandName="add" CommandArgument='<%# Eval("ProductID") %>' />
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>
// 子 Repeater 事件中取得父 Repeater 的控制項
protected void rptProducts_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    // 取得父 RepeaterItem
    RepeaterItem parentItem = e.Item.NamingContainer as RepeaterItem;
    if (parentItem != null)
    {
        // 取得父層隱藏欄位
        HiddenField hfCategoryId = parentItem.FindControl("hfCategoryId") as HiddenField;
        int categoryId = Convert.ToInt32(hfCategoryId?.Value ?? "0");
        
        // 取得當前列控制項
        TextBox txtQty = e.Item.FindControl("txtQty") as TextBox;
        // ... 業務邏輯
    }
}

3. 區分不同上下文的 ItemType

protected void rpt_ItemCommand(object source, RepeaterCommandEventArgs e)
{
    switch (e.Item.ItemType)
    {
        case ListItemType.Item:
        case ListItemType.AlternatingItem:
            // 一般資料列
            TextBox txt = e.Item.FindControl("txtQty") as TextBox;
            break;
        case ListItemType.Header:
        case ListItemType.Footer:
            // 標題/底部列 (如 Footer 含新增功能)
            TextBox txtNew = e.Item.FindControl("txtNewQty") as TextBox;
            break;
        case ListItemType.EditItem:
            // 編輯模式列 (若支援編輯樣板)
            break;
    }
}

常見錯誤與除錯技巧

錯誤現象原因解決方式
FindControl 回傳 null1. 控制項 ID 拼錯
2. 控制項不在當前 ItemTemplate 內
3. 控制項被置於 <asp:Panel> 等容器內,需先找容器再找控制項
檢查 ID 大小寫;用 e.Item.Controls 遞迴列印控制項樹確認層級
取得的值為舊值/空值1. 未在 !IsPostBack 時繫結,導致每次 PostBack 重新繫覆蓋使用者輸入
2. ViewState 未啟用
確認 if (!IsPostBack) Bind();檢查頁面/控制項 EnableViewState="true"
CommandArgument 為空CommandArgument 屬性未設定或 Eval 欄位名錯誤檢查 CommandArgument='<%# Eval("CorrectColumnName") %>'
事件未觸發1. OnItemCommand 未綁定
2. Button UseSubmitBehavior="false" 導致不回傳
3. 驗證控制項阻擋 PostBack
檢查繫結;設定 UseSubmitBehavior="true" (預設);檢查 Page.Validate()

效能優化建議

  1. 啟用 ViewState:Repeater 預設不保存資料狀態,若需 PostBack 保持輸入值,需設定 EnableViewState="true" (頁面與控制項皆需開啟)
  2. 避免在 ItemCommand 重新查詢資料庫:若僅更新單筆,考慮用 AJAX 局部更新或客戶端 JS 修改 UI,減少伺服器往返
  3. 大量資料分頁:Repeater 無內建分頁,搭配 PagedDataSource 或前端分頁插件 (DataTables.js)
  4. 輸出緩存:靜態內容可用 <%@ OutputCache %> 或資料層快取

總結

Repeater 配合 ItemCommand + e.Item.FindControl() 是 ASP.NET Web Forms 處理列表互動最經典、彈性最高的模式。掌握「透過 e.Item 定位當前命名容器,再用 FindControl 取得控制項」這一核心觀念,即可輕鬆處理單列編輯、巢狀列表、多控制項取值等各種複雜業務場景。搭配 CommandName/CommandArgument 傳遞指令與主鍵,程式碼結構清晰、易維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved