c# - Cómo manejar eventos desde Excel.OleObjects incrustado o Excel.Shapes
vb.net vba (4)
¿Has intentado usar 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);
Se hace referencia en MSDN en los foros de VSTO y en una publicación de blog anterior .
Estoy trabajando en C#
y ahora en los puertos VB.NET
de un antiguo programa VBA
. Tiene muchos MSForms/OleObjects
incrustados en ella como CommandButton
o incluso imágenes.
Mi primer pensamiento fue declarar todos los botones como Microsoft.Vbe.Interop.Forms.CommandButton
pero eso lleva a una excepción COM
que el System._COM type
no se puede convertir en ...Forms.CommandButton
. Si intento una versión más genérica de esta solución , no encuentro ningún elemento, y si trato de revisar todos los VBComponet
, tengo en cuenta que son todas las hojas del workbook
, pero ninguno de los controles:
foreach (VBComponent xxx in Globals.ThisWorkbook.VBProject.VBComponents) {
Interaction.MsgBox(xxx.Name);
Interaction.MsgBox(xxx.ToString);
}
Por lo tanto, todos estos controles no están en .VBComponets
, pero puedo encontrarlos como OLEobjects en thisworkbook.worksheets(n).OLEobjects
(esto es contraintutivo para mí, pero probablemente no entiendo el sistema para empezar).
¿Cómo manejo la acción Click de un objeto de este tipo?
Supongo que necesito usar la interfaz Excel.OLEObjectEvents_Event
, pero parece que no Excel.OLEObjectEvents_Event
entender cómo. Si intento crear eventos personalizados con delegates
, parece que no puedo asignarlos a OleObjects
. Si uso ActionClickEventHandler.CreateDelegate
, puedo obtener una gran variedad de errores que me hacen pensar que es un callejón sin salida.
La documentación oficial de MS no parece ser tan útil, aunque me introdujo en la idea de Verb
, que estoy estudiando. Hasta el momento, eso solo ha producido errores COM a lo largo de las líneas de "Error al iniciar la aplicación".
Incluso tratando de usar uno de los dos eventos estándar, .GotFocus
, siempre .GotFocus
un error 0x80040200. Ejemplo:
Excel.OLEObject ButtonCatcher = Globals.ThisWorkbook.Worksheets(1).OLEObjects("CommandButton1");
ButtonCatcher.GotFocus += CommandButton1_Click;
Lanza una Exception from HRESULT: 0x80040200
COMException Exception from HRESULT: 0x80040200
en la segunda línea. El botón está habilitado, que se comprueba después de buscar el número de código en el sitio de desarrollo de oficina.
Intentando un enfoque más genérico dentro del código para una hoja que contiene controles:
object CommandButtonStart = this.GetType().InvokeMember("CommandButton1", System.Reflection.BindingFlags.GetProperty, null, this, null);
Lanza un error del método que falta.
Cualquier ayuda es muy apreciada, esto parece que esto debería ser obvio y me estoy perdiendo.
** Editar: También descubrí que puedo convertir estos controles en Excel.Shape
pero eso no me acerca mucho más a la ejecución de una función o sub de VSTO. Estoy jugando con Excel.Shape.OnAction
pero esto requiere que se llame a un sub VBA. Supongo que podría llamar a un sub VBA que llama a un sub desde el VSTO siempre que el VSTO sea COM visible. Esto parece realmente redondo y solo me gustaría hacerlo como último recurso.
¿Puede agregar código a un módulo de código en el libro de trabajo de manera programática, como esto ?
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
Utilice el kit de herramientas de formularios de interoperabilidad. Es gratis desde Microsoft. Proporciona envoltorios com y clase de mensajería de eventos que comunica los datos del evento hacia y desde .NET a VBA. Lo he usado para controlar los eventos de control de VBA en .NET y los eventos de .NET a VBA. Usted usaría la interoperabilidad
http://www.codeproject.com/Articles/15690/VB-C-Interop-Form-Toolkit .
Desde el kit de herramientas de ducoumentación:
Interop UserControls proporciona un conjunto básico de eventos intrínsecos (Click, GotFocus, Validate, etc.) en Visual Basic 6.0. Puede definir sus propios eventos personalizados en Visual Studio .NET y aumentarlos utilizando RaiseEvent. Para manejar los eventos en Visual Basic 6.0, debe agregar una referencia de proyecto y agregar una declaración de variable WithEvents en su código, y luego manejar los eventos usando la variable WithEvents en lugar del propio control.
Cómo manejar los eventos personalizados de Interop UserControl
1. En Visual Basic 6.0, en el menú Proyecto, haga clic en Referencias. Tenga en cuenta que ya hay una referencia a ControlNameCtl, donde ControlName es el nombre de su Interop UserControl.
2. En la lista Referencias disponibles, localice una referencia para ControlName y verifíquela, y luego haga clic en Aceptar.
3. En el Editor de código, agregue una declaración para una variable WithEvents:
Dim WithEvents ControlNameEvents As ControlLibrary.ControlName
En el controlador de eventos Form_Load, agregue el siguiente código para inicializar la variable WithEvents:
Private Sub Form_Load()
Set ControlNameEvents = Me.ControlNameOnVB6Form
End Sub
Agregue código para manejar su evento personalizado en el controlador de eventos de la variable WithEvents:
Private Sub ControlNameEvents_MyCustomEvent()
MsgBox("My custom event fired")
End Sub
Tipo de solución: nivel de documento VSTO
Guión:
1.) Excel.Worksheet creado en tiempo de ejecución. (no es un elemento de host de hoja de trabajo )
2.) Agregue un botón en la hoja de trabajo en tiempo de ejecución que active el código C # cuando se haga clic.
Referencias de la asamblea:
Microsoft.Vbe.Interop (Microsoft.Vbe.Interop.dll)
Microsoft.Vbe.Interop.Forms (Microsoft.Vbe.Interop.Forms.dll)
Microsoft.VisualBasic (Microsoft.VisualBasic.dll)
Código probado / de trabajo:
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");
}