Control 基類定義 Init、Load、PreRender、Unload、DataBinding、Disposed 等生命週期事件。Click、Command、Search、FileUploaded)。public class CustomControl : WebControl
{
protected override void OnInit(EventArgs e)
{
// 1. 自訂邏輯 (註冊腳本、初始化狀態)
RegisterClientScript();
// 2. 必須呼叫基類實作,確保事件委派被引發
base.OnInit(e);
}
protected override void OnLoad(EventArgs e)
{
// 恢復 ViewState 後、回傳事件前
if (!Page.IsPostBack) InitializeDefaults();
base.OnLoad(e);
}
protected override void OnPreRender(EventArgs e)
{
// 渲染前最後調整
EnsureChildControls();
SyncVisualState();
base.OnPreRender(e);
}
protected override void OnUnload(EventArgs e)
{
// 釋放非受控資源
ReleaseResources();
base.OnUnload(e);
}
}
鐵律:覆寫 OnEventName 時一定要呼叫 base.OnEventName(e),否則訂閱該事件的委派不會被執行。
// 簡單事件
public event EventHandler Click;
// 攜帶資料事件
public event EventHandler Search;
public class SearchEventArgs : EventArgs
{
public string Keyword { get; private set; }
public SearchEventArgs(string keyword) { Keyword = keyword; }
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)Events[EventClick];
if (handler != null) handler(this, e);
}
protected virtual void OnSearch(SearchEventArgs e)
{
EventHandler handler = (EventHandler)Events[EventSearch];
if (handler != null) handler(this, e);
}
使用 Events 屬性 (EventHandlerList) 統一管理,節省記憶體。
IPostBackEventHandler.RaisePostBackEvent → 呼叫 OnClick。IPostBackDataHandler.RaisePostDataChangedEvent → 呼叫 OnTextChanged。btn_Click 處理常式中呼叫 OnSearch(new SearchEventArgs(txt.Text))。[DefaultEvent("Click")]
[ToolboxData("<{0}:CustomButton runat=server></{0}:CustomButton>")]
public class CustomButton : WebControl, IPostBackEventHandler
{
private static readonly object EventClick = new object();
private static readonly object EventCommand = new object();
public string CommandName { get; set; }
public string CommandArgument { get; set; }
public event EventHandler Click
{
add { Events.AddHandler(EventClick, value); }
remove { Events.RemoveHandler(EventClick, value); }
}
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)
{
OnClick(EventArgs.Empty);
OnCommand(new CommandEventArgs(CommandName, eventArgument));
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)Events[EventClick];
if (handler != null) handler(this, e);
}
protected virtual void OnCommand(CommandEventArgs e)
{
CommandEventHandler handler = (CommandEventHandler)Events[EventCommand];
if (handler != null) handler(this, e);
}
}
[DefaultEvent("Click")]:雙擊控制項自動產生 Click 事件處理常式。[Category("Action")]、[Description("按鈕被點擊時引發")]:屬性視窗分類與說明。[Browsable(true)]:確保事件顯示於屬性視窗 (預設即為 true)。OnBubbleEvent 攔截 CommandEventArgs 轉發為頂層事件。Command 事件至 ItemCommand (Repeater/DataList/GridView)。| 錯誤 | 原因 | 修正 |
|---|---|---|
| 事件處理常式未執行 | 未呼叫 base.OnEventName、或 Events 鍵值不一致 | 檢查 base.OnEventName(e)、static readonly object 鍵值唯一 |
| 事件在設計時不顯示 | 缺少 DefaultEvent、或事件非 public | 加上 [DefaultEvent("EventName")]、確保 public event |
| 回傳事件引發兩次 | 同時實作 IPostBackEventHandler 且子控制項也引發回傳 | 確保唯一觸發點、或使用事件屬性結構避免重複訂閱 |
ASP.NET 伺服器控制項事件系統建立在委派、EventHandlerList、生命週期虛擬方法、回傳介面四大支柱。掌握「重寫基類事件必呼叫 base、自訂事件三步驟、事件屬性結構優化、設計時屬性、冒泡路由」,即可打造功能完整、效能優異、設計時友善的專業控制項事件模型。