Подтвердить что ты не робот

Как обрабатывать события из встроенных Excel.OleObjects или Excel.Shapes

Я работаю над портами C# и теперь VB.NET старой программы VBA. В него встроено множество MSForms/OleObjects, таких как CommandButton или даже изображения.

Моей первой мыслью было объявить все кнопки как Microsoft.Vbe.Interop.Forms.CommandButton, но это привело к исключению COM, что System._COM type нельзя привести к ...Forms.CommandButton. Если я попробую более общую версию этого решения, я не найду никаких элементов, и если я попытаюсь пройти все VBComponet, я отмечу, что все они являются листами в workbook, но ни один из элементов управления:

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

Таким образом, все эти элементы управления отсутствуют в .VBComponets, но я могу найти их как OLEobjects в thisworkbook.worksheets(n).OLEobjects (для меня это противоречит здравому смыслу, но я, вероятно, не понимаю систему для начала с).

Как мне обработать действие Click от такого объекта?

Я предполагаю, что мне нужно использовать интерфейс Excel.OLEObjectEvents_Event, но я не могу понять, как это сделать. Если я пытаюсь сделать пользовательские события с delegates, я не могу назначить их на OleObjects. Если я использую ActionClickEventHandler.CreateDelegate, я могу получить огромное количество ошибок, которые заставляют меня думать, что это тупик.

официальная документация от MS не кажется такой полезной, хотя она и познакомила меня с идеей из Verb, которую я изучаю. До сих пор это вызывало только ошибки COM по типу "Приложение не удалось запустить".

Даже просто пытаясь использовать одно из двух стандартных событий, .GotFocus, я всегда получаю ошибку 0x80040200. Пример:

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

Создает исключение COMException Exception from HRESULT: 0x80040200 во второй строке. Кнопка включена, что я и проверил после просмотра кода с сайта разработчика Office.

Попытка более универсального подхода в коде для листа, содержащего элементы управления:

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

Выдает ошибку недостающего метода.

Любая помощь очень ценится, кажется, это должно быть очевидно, и я скучаю по ней.


** Редактировать: я также обнаружил, что я могу привести эти элементы управления в Excel.Shape, но это на самом деле не приближает меня к запуску функции или подпрограммы из VSTO. Я играю с Excel.Shape.OnAction, но для этого требуется саб VBA. Предположительно, я мог бы вызвать сабвуфер VBA, который вызывает сабвуфер из VSTO, если VSTO был видимым COM. Это кажется очень сложным, и я бы хотел сделать это только в крайнем случае.

4b9b3361

Ответ 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 и в старый блог пост.

Ответ 2

Тип решения: Уровень документа VSTO

Сценарий:
1.) Excel.Решет, созданный во время выполнения. (а не элемент рабочего листа)
2.) Добавить кнопку на Рабочем листе во время выполнения, которая запускает код С# при нажатии.

Ссылки на сборку:
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");
}

Ответ 3

Можете ли вы программно добавить код в CodeModule в Workbook, как это?

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

Ответ 4

Используйте инструментарий для форм interop. Это бесплатно от Microsoft. Он предоставляет com wrappers и event messenger class, который связывает данные событий с .NET и VBA. Я использовал его для обработки контрольных событий из VBA в .NET и событий от .NET до VBA. Вы должны использовать interop

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

Из инструментария ducoumentation:

Interop UserControls предоставляет базовый набор встроенных событий (Click, GotFocus, Validate и т.д.) в Visual Basic 6.0. Вы можете определить свои собственные события в Visual Studio.NET и поднять их с помощью RaiseEvent. Чтобы обрабатывать события в Visual Basic 6.0, вам нужно добавить ссылку на проект и добавить объявление переменной WithEvents в свой код, а затем обработать события, используя переменную WithEvents, а не сам элемент управления.

Как обрабатывать пользовательские события UserControl для пользователей

1. В Visual Basic 6.0 в меню "Проект" нажмите "Ссылки". Обратите внимание, что уже есть ссылка на ControlNameCtl, где ControlName - имя вашего Interop UserControl.

2. В списке "Доступные ссылки" найдите ссылку для ControlName и проверьте ее, а затем нажмите "ОК".

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