在 ASP.NET Web Forms 中,GridView 使用 ButtonType="Image" 或 ImageButton 時,點擊會觸發兩次 RowCommand / Postback,導致邏輯重複執行(如刪除兩次、雙重扣款)。此 Bug 見於 IE6/IE7/IIS 特定版本,Firefox/Chrome 較少發生,根因為 <input type="image"> 在某些瀏覽器會送出兩次請求:第一次缺少座標參數(x, y),伺服器視為無效而重試。
RowCommand 執行兩次。btnDelete.x, btnDelete.y),第二次完整。ButtonType 改為 Link 或 Button 即正常。protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
// ImageButton 第一次請求無 x, y 座標
if (Request["__EVENTTARGET"] != null &&
Request["__EVENTTARGET"].EndsWith("btnDelete") &&
(Request["btnDelete.x"] == null || Request["btnDelete.y"] == null))
{
return; // 忽略第一次無效請求
}
// 正常業務邏輯...
}
或更通用寫法:
if (Request["x"] == null && Request["y"] == null) return;
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="imgBtnDelete" runat="server"
CommandName="Delete"
CommandArgument='<%# Container.DataItemIndex %>'
ImageUrl="~/images/delete.png" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
int rowIndex = Convert.ToInt32(e.CommandArgument);
GridView1.DeleteRow(rowIndex); // 或自訂刪除邏輯
}
}
優點:避開 ButtonType="Image" 的渲染路徑,徹底解決雙重觸發。
<asp:LinkButton ID="lnkDelete" runat="server"
CommandName="Delete"
CommandArgument='<%# Container.DataItemIndex %>'
CssClass="btn-icon-delete"
OnClientClick="return confirm('確定刪除?');"></asp:LinkButton>
/* CSS */
.btn-icon-delete {
display: inline-block; width: 16px; height: 16px;
background: url('/images/delete.png') no-repeat center;
text-indent: -9999px;
}
| 控制項 | 渲染 HTML | 是否雙觸發 |
|---|---|---|
| ButtonType="Image" | <input type="image"> | ✅ 是(IE/舊 IIS) |
| ImageButton (TemplateField) | <input type="image"> | ❌ 否(微軟修正路徑) |
| LinkButton + CSS | <a href="..."> | ❌ 否 |
RowCommand 開頭加 if (Request["x"] == null) return;。