Как предоставить класс C# модулю VBA в надстройке уровня документа?

это гипотетическая ситуация.

Я хотел бы узнать, можно ли предоставить класс C# VBA в надстройке уровня документа.

вот SSCCE:

в VS PRO 2012 я начал новый проект,Выбранный Офис - > Книга Excel 2010. (убедитесь, что вы выбрали .Net framework ver 4)

я добавил DateTimePicker управление Лист1.

Я могу установить/получить .Value собственность от DateTimePicker управление в решении C# без проблем.

во время отладки: в VBA .Value недвижимость не разоблачили. (пробовал .OLEFormat.Object.Value)

enter image description here

не все свойства могут быть подвержены VBA, потому что элемент управления ActiveX DateTimePicker обернут MSForms таким образом, Excel распознает его (совместимость).

I необходимо иметь возможность захватить фактическое значение обернутого элемента управления из VBA, но я не уверен, как это сделать (возможно это или нет)...

Я знаю, что сам элемент управления поддерживает мероприятия, но это не тот путь, который я хочу взять. Я хочу иметь возможность захватить статическое / текущее значение с элемента управления.


это то, что я хотел бы иметь возможность сделать:

  • добавить класс в мой C# решение

  • разоблачить его, поэтому он воссоздается из VBA, как Dim obj as new MyExposedClass

  • есть MyExposedClass хранить ссылку на DateTimePicker как он отображается в C# (все свойства доступны)
  • тогда я могу определить функцию GetValue(string controlName) который возвращает значение из C# POV


я нашел данное решение + (этот один) это, кажется, работает с приложения-уровень надстройка, но она не работает с документ-уровень надстройки.

когда я отлаживаю свое решение и открываю браузер объектов VBA, я вижу, что ссылки автоматически добавляются в Microsoft Visual Studio 2008 Tools for Office Execution Engine 9.0 Type Library но я не думаю, что могу добавить к этому дополнительный класс...

когда я открываю ссылки в VBE, в проект не добавляются дополнительные ссылки, но в / debug папка моего решения есть ExcelWorkbook1.dll так как же это, что даже прилагается к решению?

Итак, мой вопрос:

как я могу предоставить класс в надстройке уровня документа для Excel с помощью C# для расширения диапазона свойств, доступных по умолчанию в элементах управления .Net?

обновление:

это самое близкое, что я получил до сих пор, но это позволяет вам выставлять только хост-элемент, такой как рабочий лист, книга, Диаграмма и т. д. Это позволяет вызовите методы, хотя я собираюсь исследовать это дальше и вернуться с некоторой обратной связью

вызывающий код в настройках уровня документа из VBA

как: предоставить код VBA в проекте Visual C#

Пошаговое Руководство: вызов кода из VBA в проекте Visual C#

1 ответов


вам нужно будет создать открытый интерфейс, чтобы предоставить класс VBA, это работает для меня как надстройка уровня документа.

  1. откройте новую книгу Excel и скопируйте следующее В модуль

    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. также добавьте следующее В Лист1.cs

    protected override object GetAutomationObject()
    {
        return this;
    }
    
  8. над открытым частичным классом Sheet1 в Лист1.cs добавьте следующее

    [System.Runtime.InteropServices.ComVisible(true)]
    [System.Runtime.InteropServices.ClassInterface( 
        System.Runtime.InteropServices.ClassInterfaceType.None)]
    
  9. теперь вам нужно создать открытый интерфейс для метода. В Лист1.cs щелкните правой кнопкой мыши выберите рефакторинг, извлеките интерфейс и проверьте общедоступный метод GetDatePickerVal

  10. сделать интерфейс общедоступным и COM видимым

    [System.Runtime.InteropServices.ComVisible(true)]
    public interface ISheet1
    {
        DateTime GetDatePickerVal();
    }
    
  11. дважды щелкните Лист1.cs, поэтому лист Excel виден. Выберите любую ячейку, чтобы открыть окно Свойства и их изменение ReferenceAssemblyFromVbaProject = true

  12. в Excel вам может потребоваться перейти к настройкам Центра доверия и добавить папку VS Solution и вложенные папки в качестве надежного местоположения

  13. запустите проект, и код в модуле Excel вернет dateTimepicker через открытый GetDatePickerVal метод.

enter image description here

Лист1.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();
    }
}