當控制項需響應使用者動作(按鈕點擊、連結點選、自訂命令)觸發回傳,並提供伺服器端事件給頁面開發者訂閱,必須實作 IPostBackEventHandler 介面:
public interface IPostBackEventHandler
{
void RaisePostBackEvent(string eventArgument);
}
public class CustomButton : WebControl, IPostBackEventHandler
{
public event EventHandler Click;
public void RaisePostBackEvent(string eventArgument)
{
OnClick(EventArgs.Empty);
}
protected virtual void OnClick(EventArgs e)
{
if (Click != null) Click(this, e);
}
}
頁面框架依 name=UniqueID 識別觸發回傳的控制項。渲染時必須輸出:
name="UniqueID":識別碼。onclick="__doPostBack('UniqueID', '')":觸發回傳的用戶端腳本(或 href="javascript:__doPostBack(...)")。protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
// 關鍵:輸出回傳腳本
string postBackRef = Page.ClientScript.GetPostBackEventReference(this, string.Empty);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, postBackRef);
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
}
直接宣告 public event EventHandler Click; 會為每個控制項實例配置委派欄位,大量控制項時浪費記憶體。事件屬性結構 使用 EventHandlerList (鍵/值儲存) 集中管理:
public class CustomButton : WebControl, IPostBackEventHandler
{
private static readonly object EventClick = new object();
private EventHandlerList _events = new EventHandlerList();
public event EventHandler Click
{
add { _events.AddHandler(EventClick, value); }
remove { _events.RemoveHandler(EventClick, value); }
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)_events[EventClick];
if (handler != null) handler(this, e);
}
public void RaisePostBackEvent(string eventArgument)
{
OnClick(EventArgs.Empty);
}
}
EventHandlerList 來自 System.ComponentModel,Component 基類已內建 Events 屬性,自訂控制項可繼承 Component 或自行建立欄位。[ToolboxData("<{0}:CommandButton runat=server></{0}:CommandButton>")]
public class CommandButton : WebControl, IPostBackEventHandler
{
private static readonly object EventCommand = new object();
private EventHandlerList _events = new EventHandlerList();
public string CommandName { get; set; }
public string CommandArgument { get; set; }
public event CommandEventHandler Command
{
add { _events.AddHandler(EventCommand, value); }
remove { _events.RemoveHandler(EventCommand, value); }
}
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name, UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
string postBackRef = Page.ClientScript.GetPostBackEventReference(this, CommandArgument);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, postBackRef);
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
}
public void RaisePostBackEvent(string eventArgument)
{
OnCommand(new CommandEventArgs(CommandName, eventArgument));
}
protected virtual void OnCommand(CommandEventArgs e)
{
CommandEventHandler handler = (CommandEventHandler)_events[EventCommand];
if (handler != null) handler(this, e);
}
}
使用:<cc:CommandButton CommandName="Delete" CommandArgument='<%# Eval("ID") %>' Text="刪除" OnCommand="btn_Command" runat="server" />
GetPostBackEventReference(control, argument) 產生 __doPostBack('UniqueID', 'argument')。eventArgument 參數即為第二個引數。RaisePostBackEvent 解析。[DefaultEvent("Click")] 或 [DefaultEvent("Command")] 指定預設事件,雙擊控制項自動產生事件處理常式。[Category("Action")]、[Description("按鈕點擊時引發")]。| 問題 | 原因 | 修正 |
|---|---|---|
| RaisePostBackEvent 未被呼叫 | 渲染缺少 name=UniqueID、或缺少 __doPostBack 腳本 | 檢查 Render 方法、確認 Page.Form 不為 null (需在 form runat=server 內) |
| 事件引數為空 | GetPostBackEventReference 第二參數未傳遞、或 CommandArgument 未設定 | 確認渲染邏輯正確傳遞引數 |
| 事件處理常式未觸發 | 事件屬性結構鍵值不一致、或 Events 集合未正確初始化 | 使用 static readonly object 作為鍵、確保 _events 實例化 |
實作 IPostBackEventHandler 讓自訂控制項具備「觸發回傳 → 伺服器識別 → 引發事件」完整能力。掌握「正確渲染回傳腳本 → 事件屬性結構優化 → CommandEventArgs 傳遞引數」三大核心,即可打造專業級、記憶體高效、設計時友善的互動型伺服器控制項。