如何在WinForms(.Net4.6.1)中订阅Excel的Workbook.SheetActivate事件?
在.NET 4.6.1 WinForms中动态订阅Excel SheetActivate事件的解决方案
问题描述
我希望将Excel应用作为动态对象使用(不依赖特定版本),订阅其Workbook.SheetActivate事件。
实例化与事件处理代码
public static dynamic NewInstance() { Type excelType = Type.GetTypeFromProgID("Excel.Application"); return Activator.CreateInstance(excelType); } private static void Excel_SheetActivate(dynamic Sh) { Sh.Protect("test"); }
场景差异
- .NET 5控制台应用:运行以下代码完全正常
static void Main(string[] args) { dynamic excel = NewInstance(); excel.SheetActivate += new Action<object>((obj) => Excel_SheetActivate(obj)); }
- .NET 4.6.1 WinForms应用:运行以下代码报错
public Form1() { InitializeComponent(); dynamic excel = NewInstance(); excel.SheetActivate += new Action<object>((obj) => Excel_SheetActivate(obj)); }
报错信息
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The System.Action<object> type cannot be implicitly converted to Microsoft.Office.Interop.Excel.AppEvents_SheetActivateEventHandler'.
对象类型差异
Console: dynamic {System.__ComObject} Winforms: dynamic {Microsoft.Office.Interop.Excel.ApplicationClass}
解决方案
问题根源是.NET Framework WinForms项目中,动态对象实际是强类型的Microsoft.Office.Interop.Excel.ApplicationClass,它的SheetActivate事件要求使用专属的AppEvents_SheetActivateEventHandler委托,而非通用的Action<object>。以下是两种解决方式:
方法一:完全动态创建委托(无版本依赖)
通过反射获取Excel事件委托类型,再创建委托绑定到处理方法,全程不依赖特定版本的Interop引用:
public Form1() { InitializeComponent(); dynamic excel = NewInstance(); // 获取Excel SheetActivate事件对应的委托类型 Type eventHandlerType = Type.GetTypeFromProgID("Excel.AppEvents_SheetActivateEventHandler"); // 创建委托实例,绑定到静态的Excel_SheetActivate方法 Delegate handler = Delegate.CreateDelegate( eventHandlerType, typeof(Form1).GetMethod("Excel_SheetActivate", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) ); // 订阅事件 excel.SheetActivate += handler; }
方法二:显式使用Interop委托类型(需引用程序集)
如果项目中已引用Excel Interop程序集,可直接使用对应的委托类型:
public Form1() { InitializeComponent(); dynamic excel = NewInstance(); excel.SheetActivate += new Microsoft.Office.Interop.Excel.AppEvents_SheetActivateEventHandler(Excel_SheetActivate); }
注意:方法一完全满足“不依赖特定版本”的需求,方法二则需要确保引用的Interop版本与目标环境兼容。
内容的提问来源于stack exchange,提问作者fikewek832
相关产品推荐
相关产品推荐

