事件驅動是GUI編程的核心邏輯。當程序被按鈕點擊、按鍵或定時器中斷時,如何規范處理事件?.NET框架通過EventHandler委托給出了標準答案。
🔍 一、EventHandler委托:事件處理的基石
public delegate void EventHandler(object sender, EventArgs e);
參數解析:
- object sender → 事件源對象(任意類型)
- EventArgs e → 事件數據容器(默認為空)
核心特性: - 強制統一簽名:所有事件處理器必須匹配此參數結構
- 返回值必須為void
- EventArgs是空殼基類,實際數據需通過派生類擴展
💡 設計意義:通過標準化參數,實現事件處理接口的統一化,避免簽名混亂。
?? 二、基礎事件實現(無數據傳遞)
// 發布者
class Incrementer {public event EventHandler CountedADozen; // 聲明標準事件 public void DoCount() {for(int i=1; i<100; i++)if(i%12 == 0 && CountedADozen != null)CountedADozen(this, null); // 觸發事件(無數據)}
}// 訂閱者
class Dozens {void IncrementDozensCount(object source, EventArgs e) {DozensCount++; // 忽略參數e }
}
適用場景:僅需事件通知,無需傳遞額外數據(如界面按鈕點擊)
🚀 三、擴展事件數據:自定義EventArgs
步驟詳解:
1?? 創建派生類存儲數據
public class IncrementerEventArgs : EventArgs {public int IterationCount { get; set; } // 自定義數據屬性
}
2?? 使用泛型委托聲明事件
class Incrementer {// 泛型委托綁定自定義參數類型 public event EventHandler<IncrementerEventArgs> CountedADozen;
}
3?? 觸發事件時傳遞數據
public void DoCount() {var args = new IncrementerEventArgs(); // 創建數據對象 for(int i=1; i<100; i++) {if(i%12 == 0 && CountedADozen != null) {args.IterationCount = i; // 設置數據 CountedADozen(this, args); // 傳遞數據對象 }}
}
4?? 訂閱者接收數據
void IncrementDozensCount(object source, IncrementerEventArgs e) {Console.WriteLine($"觸發位置:{e.IterationCount}"); // 使用自定義數據
}
?? 命名規范:自定義類名需以EventArgs結尾
🔄 四、事件處理程序管理
動態增刪處理器:
// 添加處理器
p.SimpleEvent += s.MethodA;
p.SimpleEvent += s.MethodB;// 移除指定處理器
p.SimpleEvent -= s.MethodB;
關鍵規則:
- 同個處理器多次注冊時,-=只移除最后一次注冊
- 事件觸發前必須檢查null(避免空引用異常)
- 線程安全場景需使用Invoke同步調用
場景 | 方案 | 示例 |
---|---|---|
無數據傳遞 | 原生EventHandler | 按鈕點擊事件 |
需傳遞數據 | EventHandler+自定義EventArgs | 進度條數值更新 |
多訂閱者管理 | +=/-=動態注冊 | 動態加載模塊 |
// 終極模板
public event EventHandler<CustomEventArgs> MyEvent;
public class CustomEventArgs : EventArgs { ... }
🚀 行動建議:
- 立即重構舊事件代碼,采用標準模式
- 復雜數據場景務必使用自定義EventArgs
- 關鍵事件添加try-catch異常處理