c# - 如何(或可能)从通过 VSTO 添加到 Excel 的功能区调用 VBA(子或函数)
问题描述
我正在开发一个项目,其中有一个 Visual Studio C# Excel 插件项目 (VSTO)。从 VSTO 代码中,我将带有按钮的功能区添加到 Excel (Office.IRibbonExtensibility)。通过 Excel 中添加的按钮,我可以对 C# 代码(在 VSTO 插件中)中的方法进行回调调用。我正在寻找(而不是寻找)从该按钮调用 VBA(函数的子函数)到 Excel 文件中的 VBA 代码的方法。换句话说,通过该按钮,我知道如何调用 C# 中的代码,但不知道如何调用 Excel 文件本身中的 VBA 代码。我花了相当长的时间搜索信息并测试一些盲目的想法,但没有成功找到任何东西或从我的测试中获得一些好的结果。我将不胜感激朝着正确的方向迈进。
不确定这是否是稍后添加此内容的正确位置和方式(2/10/20 @17:08 GMT -7)注释(在获得以下答案后)。我创建了一个小型演示项目并将其上传到 github。项目中也有一个视频(mp4)文件来展示它是如何工作的。 https://github.com/MNemteanu/ExcelVSTOAddInDemo
解决方案
这个有可能。
您必须注意,VBA 代码存储在特定的工作簿中,而 VSTO 加载项在应用程序中加载,尽管有活动的工作簿。除非开发人员知道,否则两者都不知道对方。
为了实现这样的交互,您必须了解以下内容:
1. 宏保存工作簿的名称;
2. 宏名。
知道了这一点,您将能够应用在 3d 评论中发布的解决方案。
下面是一个例子。
前提条件:
1. 我已经准备好启用宏的工作簿“VBA.xlsm”;
2. 本工作簿在常规模块中有一个名为“Foo”的宏。
实现:
1、新建VSTO插件;
2. 添加名为“Ribbon1”的功能区(可视化设计器)并将其设置为具有“自定义”ControlIdType(作为名为“测试”的单独选项卡);
3. 在该功能区中添加一个名为“callVBA”的按钮,该按钮将检查书名并尝试运行工作簿的宏。
我没有向 ThisAddIn.cs 类添加任何代码。我使用的唯一代码 - 在 Ribbon 类中的按钮单击事件处理程序中:
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
这是更复杂的方法,它检查打开的工作簿并根据是否存在具有所需宏的工作簿来启用/禁用特定按钮。它还检查新打开的并处理仅包含一个Workbook_Activate
事件的最近关闭的工作簿。
如果你不做任何检查 - 你可能会得到System.Runtime.InteropServices.COMException
一个
Message=无法将焦点移至控件,因为它不可见、未启用或属于不接受焦点的类型。
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;
}
}
}
}
推荐阅读
- ios - 使用 CAKeyframeAnimation 反转 UIImageView 的旋转
- c# - 实体框架 Guid 到带有连接表的字符串
- git - 如何在我的服务器上设置 git,并从自身推送?
- symfony - Symfony 4 - 无法访问我的实体集合
- python - Python中的正则表达式在不同字母之前和之后的两个字母
- gitlab - 生成的帖子的链接在 Gitlab 中都被破坏了
- ios - 如何添加新卡/来源以条带化客户帐户?
- java - javax.xml.bind.UnmarshalException:意外元素(uri:“”,本地:“id”)。预期元素是(无)
- c# - 为什么正则表达式给我字符串的开头
- ruby-on-rails - 如何显示来自 S3/Paperclip/Heroku 的图像?