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

ASP.NET GridView ImageButton 雙重觸發 RowCommand Bug 分析與解決

     編輯:關於ASP.NET

在 ASP.NET Web Forms 中,GridView 使用 ButtonType="Image" 或 ImageButton 時,點擊會觸發兩次 RowCommand / Postback,導致邏輯重複執行(如刪除兩次、雙重扣款)。此 Bug 見於 IE6/IE7/IIS 特定版本,Firefox/Chrome 較少發生,根因為 <input type="image"> 在某些瀏覽器會送出兩次請求:第一次缺少座標參數(x, y),伺服器視為無效而重試。

現象與驗證

  • 點擊一次,伺服器端 RowCommand 執行兩次。
  • 抓包發現:第一次請求少 8 位元組(缺 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;

方案二:使用 TemplateField 包裹 ImageButton(微軟建議)

<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" 的渲染路徑,徹底解決雙重觸發。

方案三:改用 LinkButton + CSS 圖示(現代做法)

<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="...">❌ 否

建議

  1. 新專案:直接用 LinkButton + CSS 圖示 或 TemplateField 包裹 ImageButton。
  2. 舊專案快速修復:RowCommand 開頭加 if (Request["x"] == null) return;。
  3. 長期:規劃遷移至 ASP.NET Core / Razor Pages / Blazor,避開 Web Forms 歷史包袱。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved