2014-03-13 149 views
18

我正在研究C#VB.NET端口的舊VBA程序。它有很多MSForms/OleObjects嵌入它像CommandButton甚至圖像。如何處理來自嵌入式Excel.OleObjects或Excel.Shapes的事件

我首先想到的是所有的按鈕聲明爲Microsoft.Vbe.Interop.Forms.CommandButton但導致COM異常的System._COM type不能轉換爲...Forms.CommandButton。如果我嘗試的this solution更寬泛的版本,我沒有找到任何物品,如果我嘗試去通過所有VBComponet的I注意,他們是在workbook所有的牀單,但沒有控件:

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

因此,所有這些控件不是.VBComponets,但我可以找到爲他們OLEobjectsthisworkbook.worksheets(n).OLEobjects(這是counterintutive給我,但我可能不瞭解系統開始)。

如何處理來自此類對象的Click操作?

我假設我需要使用Excel.OLEObjectEvents_Event接口,但我似乎無法弄清楚如何。如果我嘗試使用delegates進行自定義事件,我似乎無法將它們分配到OleObjects。如果我使用ActionClickEventHandler.CreateDelegate,我可以得到各種各樣的錯誤,這使我認爲這是一個死路一條。

來自MS的official documentation似乎沒有什麼幫助,雖然它向我介紹了Verbidea,我正在研究它。到目前爲止,這隻會產生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函數或子。我在玩Excel.Shape.OnAction,但這需要調用VBA子。據推測,只要VSTO可以看到COM,我就可以調用一個VBA從VSTO調用子接口。這似乎真的很圓滿,我只想做它作爲最後的手段。

+2

是否建立他們是否是在工作表上的ActiveX控件?常規窗體控件(非activeX)不會顯示事件,只能通過onAction方法調用subs。您可能遇到哪些問題? – SWa

+0

幫助我的無知。我發現VBA嵌入Office軟件程序(或其他採用它的程序)中。 VBA不是獨立的。那麼,「舊的VBA程序」是什麼? – Smandoli

+0

只是旁觀,但根據我的旅行社,所有的好的「最後的度假勝地」都是「真正圓滿的」。這幾乎是一個規則。 – Smandoli

回答

0

您可以通過編程將代碼添加到工作簿中的CodeModule中嗎?like this

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 
+0

剛剛嘗試過,並拋出異常從HRESULT:0x80040200,讓我玩這一分鐘 –

+0

試圖清理這一點,少數無效的演員以及。即Me.Codename是Sheet1,但需要是int;所以改爲this.index等等。編譯它,但它不會添加任何功能的按鈕。 –

+0

如果它應該把VBA宏放在其中一個mod或sheet代碼的末尾,它似乎沒有把它們放在那裏(我檢查了所有這些)。按鈕什麼也不做,我試着用VBComp的索引來玩,但還是沒有。 –

1

您是否嘗試過使用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); 

它是在MSDN中引用的VSTO forums並在old blog post

+0

不,我會試試看。 –

+0

仍然收到0x80040200,加上本的評論,我們可能會得到它的工作。 –

+0

即使使用提升的註冊庫,仍然會出現0x80040200錯誤。看起來像一個好主意,但。發現這不難測試,創建一個ActiveX按鈕,並嘗試NewLateBinding.LateGet來拋出該錯誤。 –

0

使用interop表單工具包。它從微軟免費。它提供通信包和事件信使類,用於將事件數據傳遞給.NET以及從VBA傳遞給.NET。我用它來處理來自.NET中的VBA的控制事件,以及從.NET到VBA的事件。您可以使用interop

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

從工具箱ducoumentation:

互操作用戶控件提供了一組基本的固有事件(點擊,的GotFocus,驗證等)在Visual Basic 6.0的。您可以在Visual Studio .NET中定義自己的自定義事件,並使用RaiseEvent提升它們。爲了處理Visual Basic 6.0中的事件,您需要添加一個項目引用並在代碼中添加一個WithEvents變量聲明,然後使用WithEvents變量而不是控件本身來處理事件。

如何處理互操作的用戶控件自定義事件

1. 在Visual Basic 6.0,在項目菜單上,單擊引用。請注意,已經有對ControlNameCtl的引用,其中ControlName是您的Interop UserControl的名稱。

2. 在Available References列表中,找到ControlName的引用並檢查它,然後單擊OK。

3. 在代碼編輯器中,添加一個聲明一個WithEvents變量:

Dim WithEvents ControlNameEvents As ControlLibrary.ControlName 

在Form_Load事件處理程序中,添加以下代碼來初始化變量WITHEVENTS:

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

添加代碼以處理WithEvents變量的事件處理函數中的自定義事件:

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

解決方案類型: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"); 
} 
相關問題