在文档不受保护后访问受保护的组件

Accessing protected components after a document becomes unprotected

我想在 DocumentOpen 事件中修改文档,在适当的地方向现有文本添加一些内容控件并更改格式。这工作正常,但在受保护文档不受保护后触发 DocumentOpen 事件时变得更加复杂:

单击"Enable Editing" 开始"unprotecting" 一个文档的处理,我定义的DocumentOpen 事件此时触发。因为该事件似乎在默认未受保护的 window 打开之前触发,但是,创建内容控件仍然被认为是不可用的。当文档处于不受保护的过程中时不会成功的简单示例:

private void ThisAddIn_Startup(object sender, EventArgs e)
{
    Application.DocumentOpen += application_DocumentOpen;
}

private void application_DocumentOpen(Document doc)
{
    doc.ContentControls.Add(
        WdContentControlType.wdContentControlRichText,
        doc.Range(doc.Content.Start, doc.Content.End - 1));
}

有什么方法可以加快取消保护过程,也就是说,仍然能够执行我的代码?或者当文档编辑可用时可预见地触发的另一个事件?我查看了与保护模式相关的触发事件 in the Microsoft documentation,但没有看到任何适合我需要的事件。不幸的是,Document.Unprotect() 和更改 Document.ActiveWindow.View.Type 也没有用,因为 "Protected Mode" 似乎是完全不同的、不可编辑的 window。要求在打开文档时或之后尽快进行这些格式修改。

它不是很漂亮,但我最终通过定义一个包含我要执行的代码的委托解决了这个问题,与每个文档的容器相关联,并检查委托是否可以在内部执行 Application.WindowActivate:

public class DocumentContainer
{
    public Action ProtectedDeferredExecution { get; set; }

    public DocumentContainer(Action deferred)
    {
        ProtectedDeferredExecution = deferred;
    }
}

public partial class ThisAddIn
{
    private Dictionary<Document, DocumentContainer> DocumentContainerDict { get; set; }

    private void ThisAddIn_Startup(object sender, EventArgs e)
    {
        DocumentContainerDict = new Dictionary<Document, DocumentContainer>();
        Application.WindowActivate += application_WindowActivate;
        Application.DocumentOpen += application_DocumentOpen;
        Application.DocumentBeforeClose += application_DocumentClose;
    }

    private void application_DocumentOpen(Document doc)
    {
        // define code that is unsafe when document is protected
        Action initialization = () =>
        {
            doc.ContentControls.Add(
                WdContentControlType.wdContentControlRichText,
                doc.Range(doc.Content.Start, doc.Content.End - 1));
        };

        // if the current window isn't "protected", able to execute the unsafe code
        if (Application.ActiveProtectedViewWindow == null)
        {
            initialization();
            initialization = null;
        }

        // send either the unsafe delegate or null to the constructor
        DocumentContainerDict.Add(doc, new VersioningDocumentContainer(initialization));
    }

    private void application_WindowActivate(Document doc, Window wn)
    {
        // skip execution if the window is still protected or isn't the view we want
        if (wn.View.Type != WdViewType.wdPrintView || Application.ActiveProtectedViewWindow != null)
        {
            return;
        }

        DocumentContainer container;

        // find the document container, if any, and the delegate to execute
        if (DocumentContainerDict.TryGetValue(doc, out container)
            && container.ProtectedDeferredExecution != null)
        {
            container.ProtectedDeferredExecution();
            container.ProtectedDeferredExecution = null;
        }
    }

    // clean up
    private void application_DocumentClose(Document doc, ref bool cancel)
    {
        DocumentContainerDict.Remove(doc);
    }
}

其他元数据也可以在此容器中轻松定义(这就是我使用它的目的),因此我为使用加载项创建的每个文档创建一个。