利用索引单例实现类不同实例的独立事件处理问题
解决SAP B1表单间数据传递重复触发事件的问题
咱们先把问题的根源拆解清楚,再给出针对性的修复方案——你遇到的重复触发问题,核心是全局事件的handler堆积加上字典存储逻辑的错误导致的。
问题分析
- 你代码里的
ShareData是全局共享事件,每次FormB初始化时都会往这个事件里绑定新的ReceivingFormDatahandler。这就意味着每创建一个FormB实例,全局事件里就多一个handler,后续触发时自然会执行多次。 - 你把这个已经堆积了多个handler的全局事件存入字典,所以不管调用哪个
UniqueId对应的事件,都会触发所有堆积的handler。 - 没有在
FormB关闭时清理字典条目和handler,旧实例的handler会一直留在内存里,即使表单已经关闭。
修复方案
我们需要让每个FormB实例拥有独立的事件handler,并且在表单生命周期结束时主动清理资源:
1. 重构ShareFormDataEvent类
移除全局共享事件,让字典直接存储每个表单专属的handler实例,同时添加注销方法用于清理。
2. 调整FormB的生命周期逻辑
初始化时创建当前实例专属的handler并注册到字典;关闭表单时从字典中移除自己的条目,避免内存泄漏和残留handler。
3. 优化FormA的触发逻辑
确保只触发目标FormB实例的专属handler。
修改后的完整代码
ShareFormDataEvent类
public delegate void IFormEventHandler(IForm sender); public sealed class ShareFormDataEvent { private static readonly Lazy<ShareFormDataEvent> lazy = new Lazy<ShareFormDataEvent>(() => new ShareFormDataEvent()); private readonly Dictionary<string, IFormEventHandler> _formEventMap; public static ShareFormDataEvent Instance => lazy.Value; private ShareFormDataEvent() { _formEventMap = new Dictionary<string, IFormEventHandler>(); } // 注册表单专属的事件handler public void RegisterFormEvent(string formUniqueId, IFormEventHandler handler) { if (_formEventMap.ContainsKey(formUniqueId)) { // 若已有条目,直接替换为当前实例的handler,避免旧handler残留 _formEventMap[formUniqueId] = handler; } else { _formEventMap.Add(formUniqueId, handler); } } // 注销表单的事件handler,表单关闭时调用 public void UnregisterFormEvent(string formUniqueId) { if (_formEventMap.ContainsKey(formUniqueId)) { _formEventMap.Remove(formUniqueId); } } // 触发目标表单的专属事件 public void TriggerFormEvent(string formUniqueId, IForm sender) { if (_formEventMap.TryGetValue(formUniqueId, out var handler)) { handler?.Invoke(sender); } } }
FormB类
public class FormB : IForm { private IFormEventHandler _instanceSpecificHandler; public override void OnInitialize() { base.OnInitializeComponent(); // 创建当前实例专属的handler,绑定到自身的处理方法 _instanceSpecificHandler = new IFormEventHandler(ReceivingFormData); // 将当前实例的handler注册到字典 ShareFormDataEvent.Instance.RegisterFormEvent(_thisForm.UniqueID, _instanceSpecificHandler); } // 表单关闭时清理资源 public override void OnClose() { base.OnClose(); // 从字典中移除当前实例的handler ShareFormDataEvent.Instance.UnregisterFormEvent(_thisForm.UniqueID); _instanceSpecificHandler = null; // 释放引用,辅助GC回收 } private void ReceivingFormData(IForm sender) { // 你的数据处理逻辑 // 现在只会被当前FormB实例触发一次 } }
FormA类
public class FormA : IForm { public void buttonClick() { // 激活并获取最新创建的FormB实例 Application.ActivateForm(FormB); var targetFormB = Application.Forms.GetLastForm(FormB); if (targetFormB != null) { // 触发目标FormB实例的专属事件 ShareFormDataEvent.Instance.TriggerFormEvent(targetFormB.UniqueID, _thisForm); } } }
关键改进点
- 每个FormB实例拥有独立handler:不再共享全局事件,彻底避免handler堆积
- 显式的注册/注销机制:表单关闭时主动清理资源,防止内存泄漏和旧handler残留
- 精准的事件触发:通过UniqueId直接定位目标表单的专属handler,确保每次只触发一次
内容的提问来源于stack exchange,提问作者Leniel Luzardo
相关产品推荐
相关产品推荐

