【问题标题】:How to expose a C# class to a VBA module in a document-level add-in?如何在文档级加载项中将 C# 类公开给 VBA 模块?
【发布时间】:2014-05-12 08:23:03
【问题描述】:

这是一种假设情况。

我想知道是否可以在文档级插件中将 C# 类公开给 VBA。

这是一个 SSCCE:

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

我在 Sheet1 中添加了一个DateTimePicker 控件。

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

调试时:在 VBA 中,.Value 属性暴露。 (试过.OLEFormat.Object.Value

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

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

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


这是我希望能够做到的:

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

  • 暴露它,这样它就可以像Dim obj as new MyExposedClass一样从VBA重新创建

  • 然后让 MyExposedClass 存储对 DateTimePicker 的引用,因为它出现在 C# 中(所有属性都可用)

  • 然后我可以定义一个函数GetValue(string controlName),它从 C# POV 返回值


所以我发现this solution + (this one) 似乎适用于应用程序级插件,但不适用于文档级 加载项。

当我调试我的解决方案并打开 VBA 的对象浏览器时,我可以看到引用已自动添加到 Microsoft Visual Studio 2008 Tools for Office Execution Engine 9.0 Type Library,但我认为我不能为其添加额外的类。 ..

当我在 VBE 中打开引用时,项目中没有添加额外的引用,但在我的解决方案的 /debug 文件夹中有一个 ExcelWorkbook1.dll 那么它是如何附加到解决方案的?

所以我的问题是:

如何使用 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

【问题讨论】:

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


    【解决方案1】:

    您需要创建一个公共接口来将该类公开给 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 控件从 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。

    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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多