如何处理来自embedded式Excel.OleObjects或Excel.Shapes的事件

我正在处理旧的VBA程序的C#VB.NET端口。 它有很多MSForms/OleObjectsembedded在它像CommandButton甚至图像。

我的第一个想法是将所有的button声明为Microsoft.Vbe.Interop.Forms.CommandButton但是导致COMexception, System._COM type不能转换为...Forms.CommandButton 。 如果我尝试一个更通用的解决scheme版本,我没有find任何项目,如果我尝试通过所有的VBComponet s我注意到,他们都是workbook中的workbook ,但没有控制:

 foreach (VBComponent xxx in Globals.ThisWorkbook.VBProject.VBComponents) { Interaction.MsgBox(xxx.Name); Interaction.MsgBox(xxx.ToString); } 

因此,所有这些控件都不在.VBComponets ,但是我可以在这个工作簿中find它们作为OLEobjects thisworkbook.worksheets(n).OLEobjects (这与我是thisworkbook.worksheets(n).OLEobjects ,但我可能并不了解系统开始)。

如何处理来自这样的对象的点击操作?

我假设我需要使用Excel.OLEObjectEvents_Event接口,但我似乎无法弄清楚如何。 如果我尝试使用delegates进行自定义事件,我似乎无法将它们分配给OleObjects 。 如果我使用ActionClickEventHandler.CreateDelegate我可以得到各种各样的错误,使我认为这是一个死胡同。

来自MS的官方文档似乎并没有什么帮助,尽pipe它向我介绍了我正在研究的Verb的概念 。 到目前为止,只有“应用程序启动失败”才产生COM错误。

即使只是试图使用两个标准事件之一, .GotFocus ,我总是拉一个0x80040200错误。 例:

 Excel.OLEObject ButtonCatcher = Globals.ThisWorkbook.Worksheets(1).OLEObjects("CommandButton1"); ButtonCatcher.GotFocus += CommandButton1_Click; 

抛出一个Exception from HRESULT: 0x80040200的COMException Exception from HRESULT: 0x80040200在第二行。 该button被启用,这是我从办公室dev站点查找代码后检查。

在包含控件的工作表的代码中尝试更通用的方法 :

 object CommandButtonStart = this.GetType().InvokeMember("CommandButton1", System.Reflection.BindingFlags.GetProperty, null, this, null); 

抛出一个Missing Method错误。

任何帮助非常感谢,这似乎应该是显而易见的,我很想念它。


**编辑:我也发现我可以将这些控件转换为Excel.Shape但实际上并没有让我更接近从VSTO运行一个函数或子。 我在玩Excel.Shape.OnAction但是这需要一个VBA子被调用。 据推测,只要VSTO是COM可见,我就可以调用一个VBA从VSTO调用一个子。 这看起来真的很糟糕,我只想作为最后的手段。

你有没有尝试过使用NewLateBinding.LateGet?

 using MSForms = Microsoft.Vbe.Interop.Forms; using Microsoft.VisualBasic.CompilerServices; ... MSForms.CommandButton CommandButton1 = (MSForms.CommandButton)NewLateBinding.LateGet(Globals.ThisWorkbook.Worksheets(1), null, "CommandButton1", new object[0], null, null, null); CommandButton1.Click += new Microsoft.Vbe.Interop.Forms.CommandButtonEvents_ClickEventHandler(CommandButton1_Click); 

它在VSTO论坛的 MSDN中以及旧的博客文章中被引用。

解决schemetypes: VSTO文档级别

场景:
1.)在运行时创buildExcel.Worksheet。 (不是工作表主机项目 )
2.)在运行时在工作表上添加一个button,单击时触发C#代码。

大会参考:
Microsoft.Vbe.Interop(Microsoft.Vbe.Interop.dll)
Microsoft.Vbe.Interop.Forms(Microsoft.Vbe.Interop.Forms.dll)
Microsoft.VisualBasic(Microsoft.VisualBasic.dll)

testing/工作代码:

 using MSForms = Microsoft.Vbe.Interop.Forms; using System.Windows.Forms; ... Microsoft.Vbe.Interop.Forms.CommandButton CmdBtn; private void CreateOLEButton() { Excel.Worksheet ws = Globals.ThisWorkbook.Application.Sheets["MyWorksheet"]; // insert button shape Excel.Shape cmdButton = ws.Shapes.AddOLEObject("Forms.CommandButton.1", Type.Missing, false, false, Type.Missing, Type.Missing, Type.Missing, 500, 5, 100, 60); cmdButton.Name = "btnButton"; // bind it and wire it up CmdBtn = (Microsoft.Vbe.Interop.Forms.CommandButton)Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(ws, null, "btnButton", new object[0], null, null, null); CmdBtn.FontSize = 10; CmdBtn.FontBold = true; CmdBtn.Caption = "Click me!"; CmdBtn.Click += new MSForms.CommandButtonEvents_ClickEventHandler(ExecuteCmd_Click); } private void ExecuteCmd_Click() { MessageBox.Show("Click"); } 

你可以以编程方式将代码添加到工作簿中的CodeModule, 像这样 ?

 Private Sub CommonButton_Click(ByVal buttonName As String) MsgBox "You clicked button [" & buttonName & "]" End Sub Private Sub CreateEventHandler(ByVal buttonName As String) Dim VBComp As VBIDE.VBComponent Dim CodeMod As VBIDE.CodeModule Dim codeText As String Dim LineNum As Long Set VBComp = ThisWorkbook.VBProject.VBComponents(Me.CodeName) Set CodeMod = VBComp.CodeModule LineNum = CodeMod.CountOfLines + 1 codeText = codeText & "Private Sub " & buttonName & "_Click()" & vbCrLf codeText = codeText & " Dim buttonName As String" & vbCrLf codeText = codeText & " buttonName = """ & buttonName & "" & vbCrLf codeText = codeText & " CommonButton_Click buttonName" & vbCrLf codeText = codeText & "End Sub" CodeMod.InsertLines LineNum, codeText End Sub 

使用互操作表单工具包。 它是免费的微软。 它提供通信包和事件信使类,用于将事件数据从.NET传递到VBA。 我用它来处理来自.NET中的VBA的控制事件,以及从.NET到VBA的事件。 你会使用互操作

http://www.codeproject.com/Articles/15690/VB-C-Interop-Form-Toolkit

从工具包的激励:

Interop UserControl在Visual Basic 6.0中提供了一组基本的内部事件(Click,GotFocus,Validate等)。 您可以在Visual Studio .NET中定义自己的自定义事件,并使用RaiseEvent提升它们。 为了处理Visual Basic 6.0中的事件,您需要添加一个项目引用,并在代码中添加一个WithEventsvariables声明,然后使用WithEventsvariables而不是控件本身来处理事件。

如何处理Interop UserControl自定义事件

1.在Visual Basic 6.0中,在项目菜单上,单击引用。 请注意,已经有对ControlNameCtl的引用,其中ControlName是您的Interop UserControl的名称。

2.在可用引用列表中findControlName的引用并检查它,然后单击确定。

3.在代码编辑器中,添加一个WithEventsvariables的声明:

 Dim WithEvents ControlNameEvents As ControlLibrary.ControlName 

在Form_Load事件处理程序中,添加以下代码以初始化WithEventsvariables:

 Private Sub Form_Load() Set ControlNameEvents = Me.ControlNameOnVB6Form End Sub 

添加代码以处理WithEventsvariables的事件处理程序中的自定义事件:

 Private Sub ControlNameEvents_MyCustomEvent() MsgBox("My custom event fired") End Sub