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); }
关键修复点说明
- 强引用集合:
_boundCharts列表持有每个绑定事件的Chart对象,阻止GC回收这些对象,保证事件处理程序始终有效。 - 清理旧绑定:每次激活工作表时,先移除该工作表已有的事件绑定并从集合中删除,避免重复绑定导致多次触发,同时防止内存泄漏。
- 避免局部变量依赖:确保MyCharts实例被长期持有,不会随方法执行结束而被回收。
内容的提问来源于stack exchange,提问作者mauro85
相关产品推荐
相关产品推荐

