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

ASP.NET PleaseWaitButton 控制項:防止重複提交與等待提示最佳實踐

     編輯:關於ASP.NET

問題情境

長時間作業 (檔案上傳、報表產生、複雜運算) 期間,使用者可能重複點擊按鈕,導致重複提交、資料錯誤、伺服器過載。需在用戶端即時給予視覺回饋並禁用按鈕。

控制項設計:繼承 Button,封裝客戶端邏輯

[ToolboxData("<{0}:PleaseWaitButton runat=server>")]
public class PleaseWaitButton : Button
{
 // 等待時顯示的文字
 public string PleaseWaitText
 {
 get => ViewState["PleaseWaitText"] as string ?? "";
 set => ViewState["PleaseWaitText"] = value;
 }

 // 等待時顯示的圖片 (GIF 動畫)
 public string PleaseWaitImage
 {
 get => ViewState["PleaseWaitImage"] as string ?? "";
 set => ViewState["PleaseWaitImage"] = value;
 }

 // 顯示模式
 public enum PleaseWaitTypeEnum { TextOnly, ImageOnly, TextThenImage, ImageThenText }
 public PleaseWaitTypeEnum PleaseWaitType
 {
 get => (PleaseWaitTypeEnum)(ViewState["PleaseWaitType"] ?? PleaseWaitTypeEnum.TextOnly);
 set => ViewState["PleaseWaitType"] = value;
 }

 protected override void OnPreRender(EventArgs e)
 {
 base.OnPreRender(e);
 // 註冊客戶端腳本
 string script = @"
 function PleaseWait(btn, text, img, type) {
 var div = document.createElement('DIV');
 div.style.position = 'absolute';
 div.style.left = '0px'; div.style.top = '0px';
 div.style.width = btn.offsetWidth + 'px';
 div.style.height = btn.offsetHeight + 'px';
 div.style.backgroundColor = '#FFFFCC';
 div.style.border = '1px solid #FFCC00';
 div.style.display = 'flex';
 div.style.alignItems = 'center';
 div.style.justifyContent = 'center';
 div.style.zIndex = 1000;
 div.style.fontSize = '12px';
 div.style.color = '#CC0000';
 div.style.whiteSpace = 'nowrap';

 var html = '';
 if (type == 0 || type == 2) html += text; // TextOnly, TextThenImage
 if (type == 1 || type == 2 || type == 3) { // ImageOnly, TextThenImage, ImageThenText
 if (img) html += (html ? ' ' : '') + '';
 else html += (html ? ' ' : '') + 'Loading...';
 }
 div.innerHTML = html;

 btn.style.display = 'none';
 btn.parentNode.insertBefore(div, btn);
 btn._pleaseWaitDiv = div;
 }";
 ScriptManager.RegisterStartupScript(this, GetType(), "PleaseWaitFunc", script, true);

 // 綁定 onclick
 string waitHtml = BuildWaitHtml();
 string onclick = $"PleaseWait(this, '{EscapeJs(PleaseWaitText)}', '{EscapeJs(PleaseWaitImage)}', {(int)PleaseWaitType}); ";
 if (!string.IsNullOrEmpty(OnClientClick))
 onclick = OnClientClick + "; " + onclick;
 OnClientClick = onclick + "__doPostBack('" + ClientID + "',''); return false;";
 }

 string BuildWaitHtml()
 {
 // 由 JavaScript 動態建立,這裡僅準備參數
 return "";
 }

 string EscapeJs(string s) => s.Replace("\\", "\\\\").Replace("'", "\\'").Replace("\n", "\\n").Replace("\r", "\\r");

 protected override void Render(HtmlTextWriter writer)
 {
 // 使用 DIV 包裹,避免 display:none 影響回發
 writer.WriteBeginTag("div");
 writer.WriteAttribute("id", ClientID + "_wrapper");
 writer.Write(HtmlTextWriter.TagRightChar);
 base.Render(writer);
 writer.WriteEndTag("div");
 }
}

使用範例 (.aspx)

<%@ Register TagPrefix="cc" Namespace="MyControls" Assembly="MyControls" %>



 匯入完成!共處理 1234 筆資料。

伺服器端點擊處理

protected void btnUpload_Click(object sender, EventArgs e)
{
 // 模擬耗時作業
System.Threading.Thread.Sleep(5000); // 實際為檔案處理、資料庫操作等

 // 完成後隱藏按鈕、顯示成功訊息
btnUpload.Visible = false;
pnlSuccess.Visible = true;
}

核心設計優勢

  • DIV 包裹法:按鈕渲染在 `
    ` 內,JS 隱藏按鈕並插入等待提示 DIV,**不干擾 `__doPostBack` 回發機制** (傳統 `disabled=true` 會阻止回發)。
  • ViewState 保存屬性:跨回發自動保持等待文字/圖片設定。
  • ScriptManager 相容:支援 `UpdatePanel` 部分更新。
  • 可擴展:易於加入進度條、取消按鈕、伺服器端進度回報 (SignalR)。

現代替代方案

  • 前端框架:`btn.disabled = true; btn.innerHTML = ' 處理中...';` 配合 `fetch`/`axios`。
  • ASP.NET Core TagHelper:`` + jQuery/Vanilla JS。
  • SignalR 即時進度推播:伺服器端 `IHubContext` 發送進度,客戶端更新 UI。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved