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


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

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

Вот пример SSCCE:

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

Я добавил элемент управления DateTimePicker к листу 1.

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

при отладке: в VBA свойство .Value является не открытым. (пытался .OLEFormat.Object.Value)

Введите описание изображения здесь

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

Мне нужно иметь возможность захватить фактическое значение обернутого элемента управления из 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 10

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. в Мастере выберите Копировать существующий документ и выберите вновь созданную книгу - Тестовая версия.xlsm "
  5. На листе Excel 1 добавьте элемент управления DateTimePicker на лист из wihin VS, дважды щелкните, чтобы создать событие ValueChanged и обновить код в листе 1.cs читать

    private DateTime dtVal;
    private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
    {
        dtVal = dateTimePicker1.Value;
    }
    
  6. Все еще в листе 1.cs, добавьте открытый метод для возврата dtVal

    public DateTime GetDatePickerVal()
    {
        return dtVal;
    }
    
  7. Также добавьте следующее к листу 1.cs

    protected override object GetAutomationObject()
    {
        return this;
    }
    
  8. Выше общественный разделяемого класса в Лист1 Лист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 папка и подпапки как надежное расположение

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

Введите описание изображения здесь

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