如何将C#类公开给文档级外接程序中的VBA模块?
这是一个假设的情况。
我想知道是否可以在文档级外接程序中将C#类暴露给VBA。
这是一个SSCCE:
在VS PRO 2012中,我启动了一个新项目, 选定办公室 – > Excel 2010工作簿 。 ( 确保选择.Net framework ver 4 )
我已向Sheet1添加了DateTimePicker
控件。
我可以在C#解决方案中的DateTimePicker
控件中设置/获取.Value
属性而不会出现问题。
在调试时:在VBA中, 不公开.Value
属性。 ( 试过.OLEFormat.Object.Value
)
并非所有属性都可以向VBA公开,因为ActiveX控件DateTimePicker
由MSForms
包装,因此Excel可识别它(兼容性)。
我需要能够从VBA获取包装控件的实际值,但我不确定如何去做( 是否可能 )…
我知道控件本身支持事件,但这不是我想要的路径。 我希望能够从控件中获取静态/当前值。
这是我希望能够做到的:
-
在我的C#解决方案中添加一个类
-
公开它,所以它可以从像
Dim obj as new MyExposedClass
这样的VBADim obj as new MyExposedClass
-
然后让
MyExposedClass
存储对DateTimePicker
引用,因为它出现在C#中(所有属性都可用) -
然后我可以定义一个函数
GetValue(string controlName)
,它返回C#POV中的Value
所以我发现这个解决方案 +( 这个 )似乎适用于应用程序级外接程序,但它不适用于文档级外接程序。
当我调试我的解决方案并打开VBA的对象浏览器时,我可以看到引用被自动添加到 Microsoft Visual Studio 2008 Tools for Office Execution Engine 9.0 Type Library
但我认为我不能为它添加额外的类…
当我在VBE中打开引用时,没有额外的引用添加到项目中,但在我的解决方案的/ debug文件夹中有一个ExcelWorkbook1.dll
那么它是如何附加到解决方案的呢?
所以我的问题是:
如何使用C#在Excel的文档级外接程序中公开类,以扩展.Net控件上默认可访问的属性范围?
更新:
这是我到目前为止最接近但它只允许你公开主题项,如工作表,工作簿,图表等。它允许你调用方法,所以我将进一步调查,并回来一些反馈
从VBA调用文档级自定义中的代码
如何:在Visual C#项目中将代码暴露给VBA
演练:在Visual C#项目中从VBA调用代码
您需要创建一个公共接口以将该类公开给VBA,这对我来说是一个文档级别的插件。
-
打开一个新的Excel工作簿并将以下内容复制到MODULE中
Sub CallVSTOMethod() Dim dt As Date Dim VSTOSheet1 As DocLevelAddin.Sheet1 Set VSTOSheet1 = GetManagedClass(Sheet1) dt = VSTOSheet1.GetDatePickerVal End Sub
-
将Excel保存为“TestProj.xlsm”并关闭。
- 打开VS,新项目,Excel 20xx工作簿并将项目命名为“DocLevelAddin”
- 在向导中,选择复制现有文档并选择新创建的工作簿“TestProj.xlsm”
-
在Excel Sheet1上将DateTimePicker控件添加到来自VS的工作表,双击以创建ValueChanged事件并更新Sheet1.cs中的代码以读取
private DateTime dtVal; private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { dtVal = dateTimePicker1.Value; }
-
仍然在Sheet1.cs中,添加一个公共方法来返回dtVal
public DateTime GetDatePickerVal() { return dtVal; }
-
还要将以下内容添加到Sheet1.cs中
protected override object GetAutomationObject() { return this; }
-
在Sheet1.cs中的公共部分类Sheet1上面添加以下内容
[System.Runtime.InteropServices.ComVisible(true)] [System.Runtime.InteropServices.ClassInterface( System.Runtime.InteropServices.ClassInterfaceType.None)]
-
现在,您需要为该方法创建一个公共接口。 在Sheet1.cs中右键单击选择Refactor,Extract Interface并检查公共方法GetDatePickerVal
-
使界面公开,COM可见
[System.Runtime.InteropServices.ComVisible(true)] public interface ISheet1 { DateTime GetDatePickerVal(); }
-
双击Sheet1.cs,以便Excel工作表可见。 选择任何单元格以打开属性窗口并更改属性ReferenceAssemblyFromVbaProject = true
-
在Excel中,您可能需要转到信任中心设置并将VS解决方案文件夹和子文件夹添加为受信任位置
-
运行项目,Excel MODULE中的代码将通过公开的GetDatePickerVal方法返回dateTimepicker。
Sheet1.cs:
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml.Linq; using Microsoft.Office.Tools.Excel; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Excel = Microsoft.Office.Interop.Excel; using Office = Microsoft.Office.Core; namespace DocLevelAddin { [System.Runtime.InteropServices.ComVisible(true)] [System.Runtime.InteropServices.ClassInterface( System.Runtime.InteropServices.ClassInterfaceType.None)] public partial class Sheet1 : DocLevelAddin.ISheet1 { private void Sheet1_Startup(object sender, System.EventArgs e) { } private void Sheet1_Shutdown(object sender, System.EventArgs e) { } #region VSTO Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InternalStartup() { this.dateTimePicker1.ValueChanged += new System.EventHandler(this.dateTimePicker1_ValueChanged); this.Startup += new System.EventHandler(this.Sheet1_Startup); this.Shutdown += new System.EventHandler(this.Sheet1_Shutdown); } #endregion private DateTime dtVal; private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { dtVal = dateTimePicker1.Value; } public DateTime GetDatePickerVal() { return dtVal; } protected override object GetAutomationObject() { return this; } } }
ISheet1.cs:
using System; namespace DocLevelAddin { [System.Runtime.InteropServices.ComVisible(true)] public interface ISheet1 { DateTime GetDatePickerVal(); } }