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

自訂控件開發進階:為 UserControl 衍生類別新增自訂事件完整教學

     編輯:關於ASP.NET

繼承 UserControl 建立複合控件時,若需對外暴露專屬事件 (如「使用者按下 Shift+Click」),需完整實作 **委派 → EventArgs → 事件** 三部曲。本文以「偵測 Shift 鍵點擊」為例,逐步示範自訂事件的標準模式、命名慣例、執行緒安全與設計原則。

自訂事件三要素標準模式

// 1. 自訂 EventArgs:攜帶事件資料
public sealed class CustomClickEventArgs : EventArgs
{
    public bool IsShiftPressed { get; }
    public Point ClickLocation { get; }

    public CustomClickEventArgs(bool isShiftPressed, Point location)
    {
        IsShiftPressed = isShiftPressed;
        ClickLocation = location;
    }
}

// 2. 委派定義:符合 .NET 事件模式 (sender, e)
public delegate void CustomClickEventHandler(object sender, CustomClickEventArgs e);

// 3. 事件宣告:在控件類別中
public event CustomClickEventHandler CustomClick;

// 4. 觸發方法:保護性虛擬方法,供衍生類別覆寫
protected virtual void OnCustomClick(CustomClickEventArgs e)
{
    CustomClick?.Invoke(this, e); // C# 6+ null 條件運算子,執行緒安全
}

// 5. 實際觸發點 (例如滑鼠事件處理)
private void MyControl_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        bool shift = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
        OnCustomClick(new CustomClickEventArgs(shift, e.Location));
    }
}

使用者端訂閱事件

<uc:MyCustomControl ID="MyCtrl" runat="server" OnCustomClick="MyCtrl_CustomClick" />

// Code-behind
protected void MyCtrl_CustomClick(object sender, CustomClickEventArgs e)
{
    if (e.IsShiftPressed)
        lblMsg.Text = $"Shift+Click at {e.ClickLocation}";
    else
        lblMsg.Text = $"Normal Click at {e.ClickLocation}";
}

進階:事件存取器與大量事件優化

若控件事件極多 (如 Control 基類 70+ 事件),使用 EventHandlerList 儲存委派,避免每個事件佔用欄位:

private static readonly object EventCustomClick = new object();

public event CustomClickEventHandler CustomClick
{
    add { Events.AddHandler(EventCustomClick, value); }
    remove { Events.RemoveHandler(EventCustomClick, value); }
}

protected virtual void OnCustomClick(CustomClickEventArgs e)
{
    var handler = (CustomClickEventHandler)Events[EventCustomClick];
    handler?.Invoke(this, e);
}

此為 Component/Control 基類內建模式,Events 屬性為 EventHandlerList。

設計原則與最佳實踐

原則做法
命名慣例EventArgs 類別以 EventArgs 結尾;委派以 EventHandler 結尾;事件名稱用動詞片語 (如 CustomClick、DataLoaded)。
EventArgs 不可變屬性唯讀,透過建構函式注入,確保事件引數在多訂閱者間一致。
sender 傳 this讓訂閱者能轉型存取控件其他公開成員。
虛擬 OnXxx 方法允許衍生類別在觸發前/後插入邏輯,或完全取代觸發行為。
執行緒安全觸發使用 handler?.Invoke(this, e) 或 EventHandlerList 內建同步。
文件化XML 註解標註 <event>、<param name="e">,IntelliSense 可見。

常見錯誤與避坑

  • ❌ 直接 public EventHandler CustomClick; (欄位而非事件) → 外部可直接 = null 清除訂閱者,破壞封裝。
  • ❌ EventArgs 可變屬性 → 訂閱者修改引數影響其他訂閱者。
  • ❌ 忘記 ?.Invoke → 無訂閱者時拋 NullReferenceException。
  • ❌ 事件名稱與屬性衝突 (如 Click 屬性 vs Click 事件) → 命名加前綴區分。

結語

自訂事件是控件與外部世界溝通的契約。遵循 **EventArgs + Delegate + Event + Virtual OnXxx** 標準模式,配合 EventHandlerList 優化大量事件記憶體,能打造專業、可擴展、符合 .NET 設計規範的自訂控件。下次需要「通知外部發生了什麼」時,請優雅地定義一個事件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved