You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

利用索引单例实现类不同实例的独立事件处理问题

解决SAP B1表单间数据传递重复触发事件的问题

咱们先把问题的根源拆解清楚,再给出针对性的修复方案——你遇到的重复触发问题,核心是全局事件的handler堆积加上字典存储逻辑的错误导致的。

问题分析

  1. 你代码里的ShareData是全局共享事件,每次FormB初始化时都会往这个事件里绑定新的ReceivingFormData handler。这就意味着每创建一个FormB实例,全局事件里就多一个handler,后续触发时自然会执行多次。
  2. 你把这个已经堆积了多个handler的全局事件存入字典,所以不管调用哪个UniqueId对应的事件,都会触发所有堆积的handler。
  3. 没有在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:52:34