Это возможно.
Следует иметь в виду, что код VBA хранится в конкретной книге, в то время как надстройка VSTO загружается в приложение, несмотря на активную книгу. И никто из них не знает друг о друге, если только разработчик не знает.
Чтобы реализовать такое взаимодействие, вы должны знать следующее:
1. Макрос, содержащий имя книги;
2. Имя макроса.
Зная это, вы сможете применить решение, опубликованное в 3D-комментарии.
Ниже приведен пример.
Предварительные условия:
1. Я подготовил рабочую книгу с поддержкой макросов "VBA.xlsm" ;
2. В этой книге есть макрос под названием «Foo» в обычном модуле.
Реализация:
1. Создайте новую надстройку VSTO;
2. Добавьте ленту (Visual Designer) с именем «Ribbon1» и установите для нее «Custom» ControlIdType (чтобы он был отдельной вкладкой). под названием "Test");
3. Добавьте кнопку с именем "callVBA" на эту ленту, которая проверит название книги и попытается запустить макрос книги.
Я не добавил ни одного кода в класс ThisAddIn.cs. Единственный код, который я использовал, - это обработчик события нажатия кнопки в классе ленты:
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
}
private void callVBA_Click(object sender, RibbonControlEventArgs e)
{
if (Globals.ThisAddIn.Application.ActiveWorkbook.Name == "VBA.xlsm")
{
Globals.ThisAddIn.Application.Workbooks["VBA.xlsm"].Application.Run("Foo");
}
}
}
Это довольно просто, но требует, чтобы вы подготовили предварительные условия.
Как это работает:
Обновление 1
Вот более сложный подход, который проверяет открытые книги и включает / отключает указанную кнопку c в зависимости от того, есть ли рабочая книга с необходимым макросом Он также проверяет вновь открытые и обрабатывает недавно закрытые книги только с одним событием Workbook_Activate
.
Если вы не выполните какую-либо проверку - вы можете получить System.Runtime.InteropServices.COMException
с
Сообщение = Не удается переместить фокус на элемент управления, потому что он невидим, не включен или имеет тип, который не принимает фокус.
public partial class Ribbon1
{
private bool vbaMacroFound;
private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
{
CheckButtons();
Globals.ThisAddIn.Application.WorkbookActivate += new Excel.AppEvents_WorkbookActivateEventHandler(Workbook_Activate);
}
private void callVBA_Click(object sender, RibbonControlEventArgs e)
{
if (vbaMacroFound)
{
Globals.ThisAddIn.Application.Workbooks["VBA.xlsm"].Application.Run("Foo");
}
}
private void Workbook_Activate(Excel.Workbook Wb)
{
CheckButtons();
}
private void CheckButtons()
{
vbaMacroFound = false;
this.callVBA.Enabled = false;
this.callVBA.ScreenTip = "There is no specified macro in none of active workbooks";
foreach (Excel.Workbook book in Globals.ThisAddIn.Application.Workbooks)
{
if (book.Name.Equals("VBA.xlsm"))
{
this.callVBA.Enabled = true;
this.callVBA.ScreenTip = "Call the sub from VBA";
vbaMacroFound = true;
}
}
}
}