Как предоставить класс 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 ответ:
Вам нужно будет создать открытый интерфейс, чтобы предоставить класс 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 и назовите проект "DocLevelAddin"
- в Мастере выберите Копировать существующий документ и выберите вновь созданную книгу - Тестовая версия.xlsm "
На листе Excel 1 добавьте элемент управления DateTimePicker на лист из wihin VS, дважды щелкните, чтобы создать событие ValueChanged и обновить код в листе 1.cs читать
private DateTime dtVal; private void dateTimePicker1_ValueChanged(object sender, EventArgs e) { dtVal = dateTimePicker1.Value; }
Все еще в листе 1.cs, добавьте открытый метод для возврата dtVal
public DateTime GetDatePickerVal() { return dtVal; }
Также добавьте следующее к листу 1.cs
protected override object GetAutomationObject() { return this; }
Выше общественный разделяемого класса в Лист1 Лист1.cs добавить следующее
[System.Runtime.InteropServices.ComVisible(true)] [System.Runtime.InteropServices.ClassInterface( System.Runtime.InteropServices.ClassInterfaceType.None)]
Теперь тебе нужно ... создайте открытый интерфейс для метода. В Листе1.cs щелкните правой кнопкой мыши выбрать Рефактор, извлечь интерфейс и проверить открытый метод GetDatePickerVal
Сделать интерфейс открытым и COM видимым
[System.Runtime.InteropServices.ComVisible(true)] public interface ISheet1 { DateTime GetDatePickerVal(); }
Дважды щелкните лист 1.cs так что лист Excel виден. Выберите любую ячейку, чтобы открыть окно свойств и изменить свойство ReferenceAssemblyFromVbaProject = true
В Excel вам может потребоваться получить настройки Центра доверия и добавить решение VS папка и подпапки как надежное расположение
Запустите проект, и код в модуле 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(); } }