GridViewCommandEventArgs 不像 DataGridCommandEventArgs 直接提供 Item 屬性,需自行取得觸發行。
var btn = (Button)e.CommandSource;
var row = (GridViewRow)btn.NamingContainer; // 直接取得命名容器(即 GridViewRow)
int rowIndex = row.RowIndex;
原理:NamingContainer 指向實作 INamingContainer 的最近祖先,GridViewRow 即實作此介面。
<asp:TemplateField>
<ItemTemplate>
<asp:Button CommandName="Edit" CommandArgument='<%# Container.DataItemIndex %>' Text="編輯" />
</ItemTemplate>
</asp:TemplateField>
int rowIndex = Convert.ToInt32(e.CommandArgument);
var row = GridView1.Rows[rowIndex];
無需爬樹,直接取得索引,適合高頻操作。
<asp:ButtonField CommandName="Delete" ButtonType="Button" Text="刪除" />
ButtonField 會自動將行索引放入 e.CommandArgument,直接轉換即可:
int rowIndex = Convert.ToInt32(e.CommandArgument);
var row = GridView1.Rows[rowIndex];
注意:ButtonField 的 CommandSource 是 GridView 本身,不可用方法一。
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e) {
GridViewRow row = null;
int rowIndex = -1;
switch (e.CommandName) {
case "Edit": // TemplateField + CommandArgument
rowIndex = Convert.ToInt32(e.CommandArgument);
row = GridView1.Rows[rowIndex];
break;
case "View": // TemplateField + NamingContainer
row = ((Control)e.CommandSource).NamingContainer as GridViewRow;
break;
case "Delete": // ButtonField
rowIndex = Convert.ToInt32(e.CommandArgument);
row = GridView1.Rows[rowIndex];
break;
}
if (row != null) {
string id = GridView1.DataKeys[row.RowIndex].Value.ToString();
// 業務邏輯...
}
}
| 情境 | 推薦方法 | 理由 |
|---|---|---|
| TemplateField 按鈕 | 方法二 | 效能最好,無視覺樹依賴 |
| TemplateField 但不想設 CommandArgument | 方法一 | 通用、零前台修改 |
| ButtonField | 方法三 | 內建支援,最省事 |
RowIndex 為頁內索引,配合 DataKeys 取得真實主鍵。NamingContainer 在巢狀控件(如 GridView 在 Repeater 中)可能指向錯誤層級,優先用 CommandArgument。