我正在研究一个旧的VBA
程序的C#
和现在的VB.NET
端口。它有很多像CommandButton
甚至图片这样的MSForms/OleObjects
嵌入其中。
我的第一个想法是将所有按钮声明为Microsoft.Vbe.Interop.Forms.CommandButton
,但这导致了一个COM
异常,即System._COM type
不能转换为...Forms.CommandButton
。如果我尝试更通用的this solution版本,我没有找到任何项,如果我尝试遍历所有的VBComponet
,我注意到它们都是workbook
中的工作表,但没有任何控件:
foreach (VBComponent xxx in Globals.ThisWorkbook.VBProject.VBComponents) {
Interaction.MsgBox(xxx.Name);
Interaction.MsgBox(xxx.ToString);
}
因此,并不是所有这些控件都在.VBComponets
中,但我可以在thisworkbook.worksheets(n).OLEobjects
中找到它们作为OLEobjects (这与我的直觉相反,但我可能一开始就不理解系统)。
如何处理此类对象的操作?
我假设我需要使用Excel.OLEObjectEvents_Event
接口,但我似乎不知道如何使用。如果我尝试使用delegates
创建自定义事件,似乎无法将它们分配给OleObjects
。如果我使用ActionClickEventHandler.CreateDelegate
,我会得到各种各样的错误,这让我觉得那是个死胡同。
微软的official documentation似乎没有什么帮助,尽管它确实向我介绍了我正在研究的Verb
的idea。到目前为止,这只产生了类似于“应用程序无法启动”的COM错误。
即使只是尝试使用两个标准事件.GotFocus
中的一个,我也总是拉出0x80040200错误。示例:
Excel.OLEObject ButtonCatcher = Globals.ThisWorkbook.Worksheets(1).OLEObjects("CommandButton1");
ButtonCatcher.GotFocus += CommandButton1_Click;
在第二行抛出COMException Exception from HRESULT: 0x80040200
。该按钮处于启用状态,这是我在查找code number from the office dev site.后选中的
在包含控件的工作表的代码中尝试更多的generic approach:
object CommandButtonStart = this.GetType().InvokeMember("CommandButton1", System.Reflection.BindingFlags.GetProperty, null, this, null);
抛出一个缺少方法的错误。
任何帮助都是非常感谢的,这似乎是显而易见的,我错过了它。
**编辑:我还发现我可以将这些控件转换为Excel.Shape
,但这实际上并不能让我更接近于从VSTO运行函数或sub。我正在使用Excel.Shape.OnAction
,但这需要调用一个VBA子。假设,只要VSTO是COM可见的,我就可以调用VBA子,而VBA子调用来自VSTO的子。这似乎真的很拐弯抹角,我只想在万不得已的情况下才这么做。
发布于 2017-10-14 05:34:57
解决方案类型: VSTO Document-Level
场景:
1.)在运行时创建的Excel.Worksheet。(不是Worksheet Host Item)
2.)在运行时在工作表上添加一个按钮,该按钮在单击时触发C#代码。
程序集引用:
Microsoft.Vbe.Interop (Microsoft.Vbe.Interop.dll)
Microsoft.Vbe.Interop.Forms (Microsoft.Vbe.Interop.Forms.dll)
Microsoft.VisualBasic (Microsoft.VisualBasic.dll)
测试/工作代码:
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.Caption = "Click me!";
CmdBtn.Click += new MSForms.CommandButtonEvents_ClickEventHandler(ExecuteCmd_Click);
}
private void ExecuteCmd_Click()
{
MessageBox.Show("Click");
}
发布于 2014-03-25 02:26:41
你试过使用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 forums和old blog post中的MSDN上被引用。
发布于 2014-03-24 23:34:40
是否可以通过编程方式将代码添加到工作簿like this中的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
https://stackoverflow.com/questions/22368680
复制相似问题