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

ExcelDNA C#:Chart.MouseDown事件仅触发一次的问题排查

解决Chart.MouseDown事件仅触发一次的问题

这个问题的核心原因是**对象引用被垃圾回收(GC)**导致事件绑定失效。当你在SetAllCharts方法里绑定事件时,myChart是局部变量,方法执行完毕后如果没有其他强引用持有这个Chart对象,.NET的垃圾回收器会回收它,事件处理程序自然就无法响应后续点击了。

修复方案:维护强引用集合+规范事件绑定流程

我们需要在MyCharts类里添加一个强引用集合,保存所有绑定了事件的Chart对象,同时每次激活工作表时先清理旧绑定,避免重复绑定或内存泄漏。

修改后的MyCharts类代码

internal class MyCharts
{
    // 强引用集合,保存所有绑定了事件的Chart对象,防止GC回收
    private List<XL.Chart> _boundCharts = new List<XL.Chart>();
    private readonly XL.Application _xlapp;

    // 构造函数注入Excel应用实例
    public MyCharts(XL.Application xlapp)
    {
        _xlapp = xlapp;
    }

    internal void SetAllCharts(object obj_Ws)
    {
        XL.Worksheet ws = (XL.Worksheet)obj_Ws;
        XL.ChartObjects chartObjects = ws.ChartObjects();

        // 先清理当前工作表已绑定的旧事件和引用,避免重复绑定
        var chartsToRemove = _boundCharts.Where(c => c.Parent.Parent == ws).ToList();
        foreach (var chart in chartsToRemove)
        {
            chart.MouseDown -= MyChart_MouseDown;
            _boundCharts.Remove(chart);
        }

        if (chartObjects.Count > 0)
        {
            _xlapp.StatusBar = $"Setting {chartObjects.Count} charts";
            
            foreach (XL.ChartObject chartObj in chartObjects)
            {
                XL.Chart myChart = chartObj.Chart;
                // 先移除可能存在的旧绑定,防止重复触发
                myChart.MouseDown -= MyChart_MouseDown;
                // 绑定新的事件处理程序
                myChart.MouseDown += MyChart_MouseDown;
                // 将Chart对象加入强引用集合
                _boundCharts.Add(myChart);
            }
        }
    }

    private void MyChart_MouseDown(XL.MouseButton button, XL.ShiftState shift, int x, int y)
    {
        _xlapp.StatusBar = $"Clicked at X: {x}, Y: {y}";
    }
}

确保MyCharts实例被长期持有

还要注意,你的MyCharts实例不能是局部变量,必须由Add-in的长期存在对象持有(比如ThisAddIn类),否则实例本身被回收后,强引用集合也会失效:

// 在ThisAddIn类中
private MyCharts _myCharts;

private void ThisAddIn_Startup(object sender, EventArgs e)
{
    _myCharts = new MyCharts(this.Application);
    this.Application.SheetActivate += Xlapp_SheetActivate;
}

private void Xlapp_SheetActivate(object obj_Ws)
{
    _myCharts.SetAllCharts(obj_Ws);
}

关键修复点说明

  1. 强引用集合:_boundCharts列表持有每个绑定事件的Chart对象,阻止GC回收这些对象,保证事件处理程序始终有效。
  2. 清理旧绑定:每次激活工作表时,先移除该工作表已有的事件绑定并从集合中删除,避免重复绑定导致多次触发,同时防止内存泄漏。
  3. 避免局部变量依赖:确保MyCharts实例被长期持有,不会随方法执行结束而被回收。

内容的提问来源于stack exchange,提问作者mauro85

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:38:24