如何将C#类公开给文档级外接程序中的VBA模块?

时间:2014-04-01 13:51:10

标签: c# vba vsto add-in office-interop

这是一种假设情况。

我想知道是否可以在文档级外接程序中将C#类公开给VBA。

这是一个SSCCE:

在VS PRO 2012中,我开始了一个新项目Selected Office -> Excel 2010 Workbook。 (make sure you select .Net framework ver 4

我在Sheet1中添加了DateTimePicker控件。

我可以在C#解决方案中设置/获取.Value属性,而不会出现问题。

调试时:在VBA中,DateTimePicker属性公开。 (尝试.Value

enter image description here

并非所有属性都可以向VBA公开,因为ActiveX控件.OLEFormat.Object.ValueDateTimePicker包装,因此Excel可识别它(兼容性)。

我需要能够从VBA获取包装控件的实际值,但我不确定如何去做(是否可能< / EM>)...

我知道控件本身支持事件,但这不是我想要的路径。我希望能够从控件中获取静态/当前值。


这是我希望能够做到的:

  • 在我的C#解决方案中添加一个类

  • 公开它,因此可以从MSForms

  • 等VBA中重新学习
  • 然后Dim obj as new MyExposedClass存储对MyExposedClass的引用,因为它出现在C#中(所有可用属性)

  • 然后我可以定义一个函数DateTimePicker,它返回来自C#POV的值


所以我发现this solution +(this one)似乎与应用程序级加载项一起使用,但它不适用于文档 - 级别加载项。

当我调试我的解决方案并打开VBA的对象浏览器时,我可以看到引用会自动添加到 GetValue(string controlName) 但我不认为我可以为它添加一个额外的类......

当我在VBE中打开引用时,没有额外的引用添加到项目中但在我的解决方案的/ debug文件夹中有一个Microsoft Visual Studio 2008 Tools for Office Execution Engine 9.0 Type Library所以它如何附加到解决方案?

所以我的问题是:

如何使用C#在Excel的文档级外接程序中公开类,以扩展.Net控件上默认可访问的属性范围?

更新

这是我到目前为止最接近但它只允许你公开主题项,如工作表,工作簿,图表等。它允许你调用方法,所以我将进一步调查这一点,然后回来一些反馈

Calling Code in Document-Level Customizations from VBA

How to: Expose Code to VBA in a Visual C# Project

Walkthrough: Calling Code from VBA in a Visual C# Project

1 个答案:

答案 0 :(得分:6)

您需要创建一个公共接口以将该类公开给VBA,这对我来说是一个文档级别的插件。

  1. 打开一个新的Excel工作簿并将以下内容复制到MODULE

    Sub CallVSTOMethod()
    Dim dt As Date
    Dim VSTOSheet1 As DocLevelAddin.Sheet1
        Set VSTOSheet1 = GetManagedClass(Sheet1)
        dt = VSTOSheet1.GetDatePickerVal
    End Sub
    
  2. 将Excel保存为“TestProj.xlsm”并关闭。

  3. 打开VS,新项目,Excel 20xx工作簿并将项目命名为“DocLevelAddin”
  4. 在向导中,选择复制现有文档并选择新创建的工作簿“TestProj.xlsm”
  5. 在Excel Sheet1上将DateTimePicker控件添加到来自wihin VS的工作表中,双击以创建ValueChanged事件并更新Sheet1.cs中的代码以读取

    private DateTime dtVal;
    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dtVal = dateTimePicker1.Value;
    }
    
  6. 仍然在Sheet1.cs中,添加一个公共方法来返回dtVal

    public DateTime GetDatePickerVal()
    {
        return dtVal;
    }
    
  7. 还将以下内容添加到Sheet1.cs

    protected override object GetAutomationObject()
    {
        return this;
    }
    
  8. 在Sheet1.cs上面的公共部分类Sheet1上面添加以下内容

    [System.Runtime.InteropServices.ComVisible(true)]
    [System.Runtime.InteropServices.ClassInterface( 
        System.Runtime.InteropServices.ClassInterfaceType.None)]
    
  9. 现在您需要为该方法创建一个公共接口。在Sheet1.cs中右键单击选择Refactor,Extract Interface并检查公共方法GetDatePickerVal

  10. 使界面公开,COM可见

    [System.Runtime.InteropServices.ComVisible(true)]
    public interface ISheet1
    {
        DateTime GetDatePickerVal();
    }
    
  11. 双击Sheet1.cs以显示Excel工作表。选择任何单元格以打开属性窗口并更改属性ReferenceAssemblyFromVbaProject = true

  12. 在Excel中,您可能需要转到信任中心设置并将VS解决方案文件夹和子文件夹添加为受信任位置

  13. 运行项目,Excel MODULE中的代码将通过公开的GetDatePickerVal方法返回dateTimepicker。

  14. enter image description here

    <强> 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
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            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();
        }
    }