我有一个 C# 帮助程序类 (
ExcelMacroHelper
),可帮助将 VBA 宏代码注入到打开的 Excel 工作簿中并运行生成的宏。 我刚刚意识到以下步骤会破坏我的代码:
C# 应用程序将宏代码注入到活动工作簿中,这会导致
ExcelMacroHelper
将其状态标记为准备运行宏用户切换到 Excel 中的不同工作簿。
C# 应用程序尝试运行宏。
ExcelMacroHelper
会认为它已准备好运行宏,但 VBA 代码被注入到不同的工作簿中,因此调用将失败。要解决此问题,我认为我需要某种方法在
Workbook
对象上设置临时属性,指示我的宏代码已注入其中,或者至少需要一种维护已注入的 Workbook
列表的方法处理。 有什么想法吗?
您可以使用名称来保存值(以及范围引用等)
伪代码
if not (name already exists) then
Set nm = workbook.Names.add("Injected")
nm.Value = False
nm.Visable = False
end if
if nm.value = False
//Inject Code
nm.value = true
endif
注意:测试名称是否存在的最简单方法是尝试访问它,如果不存在则处理错误
我最终使用了自定义文档属性。 像这样的东西:
private bool needToInjectMacroCode() {
// Get custom document property with name tagPropertyName
object properties, property, propertyValue;
properties = excel.ActiveWorkbook.GetType().InvokeMember(
"CustomDocumentProperties",
BindingFlags.Default | BindingFlags.GetProperty,
null, excel.ActiveWorkbook, null);
try {
property = properties.GetType().InvokeMember(
"Item",
BindingFlags.Default | BindingFlags.GetProperty,
null, properties, new object[] { tagPropertyName });
} catch (TargetInvocationException) {
return true;
}
propertyValue = property.GetType().InvokeMember(
"Value",
BindingFlags.Default | BindingFlags.GetProperty,
null, property, null);
return (tagString != (propertyValue as string));
}
// ...
private void setMacroCodeInjected() {
// Set custom property with name tagPropertyName to value tagString
object properties = excel.ActiveWorkbook.GetType().InvokeMember(
"CustomDocumentProperties",
BindingFlags.Default | BindingFlags.GetProperty,
null, excel.ActiveWorkbook, null);
try {
properties.GetType().InvokeMember(
"Add",
BindingFlags.Default | BindingFlags.InvokeMethod,
null, properties, new object[] {
tagPropertyName, false,
Office.MsoDocProperties.msoPropertyTypeString,
tagString
});
} catch (TargetInvocationException) {
object property = properties.GetType().InvokeMember(
"Item",
BindingFlags.Default | BindingFlags.GetProperty,
null, properties, new object[] { tagPropertyName });
property.GetType().InvokeMember(
"Value",
BindingFlags.Default | BindingFlags.SetProperty,
null, property, new object[] { tagString });
}
}
Its a bit old but you could consider declaring a variable in AddIn.cs and access it elsewhere
For e.g. when I am downloading data I don't want to track changes on excel
public partial class ThisAddIn
{
public bool WorkbookLoadStatus { get; set; } = true;
}
private void DownloadDataFromSQL()
{
// Set the status to false while downloading data
Globals.ThisAddIn.WorkbookLoadStatus = false;
// Your data download code here
// After download completes, set the status to true to allow tracking changes
Globals.ThisAddIn.WorkbookLoadStatus = true;
}
private void AnotherMethod()
{
if (Globals.ThisAddIn.WorkbookLoadStatus == false)
{
// Perform some action when WorkbookLoadStatus is false
}
}
关键是Globals.ThisAddIn.WorkbookLoadStatus