如何处理来自embedded式Excel.OleObjects或Excel.Shapes的事件
我正在处理旧的VBA
程序的C#
和VB.NET
端口。 它有很多MSForms/OleObjects
embedded在它像CommandButton
甚至图像。
我的第一个想法是将所有的button声明为Microsoft.Vbe.Interop.Forms.CommandButton
但是导致COM
exception, 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