有没有办法在 Excel 工作簿对象上设置临时标志?

问题描述 投票:0回答:4

我有一个 C# 帮助程序类 (

ExcelMacroHelper
),可帮助将 VBA 宏代码注入到打开的 Excel 工作簿中并运行生成的宏。 我刚刚意识到以下步骤会破坏我的代码:

  1. C# 应用程序将宏代码注入到活动工作簿中,这会导致

    ExcelMacroHelper
    将其状态标记为准备运行宏

  2. 用户切换到 Excel 中的不同工作簿。

  3. C# 应用程序尝试运行宏。

    ExcelMacroHelper
    会认为它已准备好运行宏,但 VBA 代码被注入到不同的工作簿中,因此调用将失败。

要解决此问题,我认为我需要某种方法在

Workbook
对象上设置临时属性,指示我的宏代码已注入其中,或者至少需要一种维护已注入的
Workbook
列表的方法处理。 有什么想法吗?

c# excel vba interop
4个回答
1
投票

您可以使用名称来保存值(以及范围引用等)

伪代码

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

注意:测试名称是否存在的最简单方法是尝试访问它,如果不存在则处理错误


0
投票

您可以使用 WorkbookTag 属性。

当你注入代码时,你可以这样做:

public class ExcelMacroHelper
{
   public static void Inject(Workbook workbook)
   {
       if ((workbook.Tag as String != "Injected"))
       {
          //Inject the code

           workbook.Tag = "Injected";
       }
   }
}

0
投票

我最终使用了自定义文档属性。 像这样的东西:

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

0
投票
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

© www.soinside.com 2019 - 2024. All rights reserved.