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

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

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

Здесь SSCCE:

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

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

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

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

enter image description here

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

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

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


Вот что я хотел бы сделать:

  • Добавить класс в мое решение С#

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

  • затем MyExposedClass сохраните ссылку на DateTimePicker, как показано на С# (все доступные свойства)

  • то я могу определить функцию GetValue(string controlName), которая возвращает значение из С# POV


Итак, я нашел это решение + ( Вызов кода в настройках уровня документа из VBA

Как открыть код VBA в Visual С# Project

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

Ответ 1

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

  • Откройте новую книгу Excel и скопируйте следующее в МОДУЛЬ

    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 Workbook и назовите проект "DocLevelAddin"
  • В мастере выберите копию существующего документа и выберите новую созданную книгу "TestProj.xlsm"
  • На листе Excel1 добавьте элемент DateTimePicker на лист из wihin 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 в Sheet1.cs добавьте следующие

    [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 вернет DateTimepicker через открытый метод GetDatePickerVal.

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