在VSTO Word插件中为多个文档创建和管理自定义任务窗格 [英] Creating and managing custom task panes for multiple documents in a VSTO Word addin

查看:307
本文介绍了在VSTO Word插件中为多个文档创建和管理自定义任务窗格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Visual Studio 2008中使用VSTO开发Word 2007-2010加载项.在我的加载项中,我需要每个打开的Word文档的自定义任务窗格.基本上,我需要为每个文档创建一个任务窗格,在文档窗口中显示正确的任务窗格,在文档关闭时执行一些操作,然后删除该任务窗格及其所有引用.

I'm developing a Word 2007-2010 addin using VSTO in Visual Studio 2008. In my addin, I need a custom task pane for each open word document. Basically, I need to create a task pane for each document, show the correct task pane in the document window, do something on document close and then remove the task pane and all references to it.

这是我到目前为止所做的:

This is what I have done so far:

任务窗格创建

我为加载的每个新文档,打开文档或现有文档创建一个自定义任务窗格,如下所示:

I create a custom task pane for each new, opened or existing on load document like this:

((ApplicationEvents4_Event) Application).NewDocument += CreateTaskPaneWrapper;
Application.DocumentOpen += CreateTaskPaneWrapper;
foreach (Document document in Application.Documents)
{
    CreateTaskPaneWrapper(document);
}

在CreateTaskPaneWrapper方法中,我检查一个Dictionary< Document,TaskPaneWrapper>如果文档的任务窗格已经存在.我这样做是因为如果尝试打开已经打开的文档,则会触发open事件.如果不存在,则创建一个新的TaskPaneWrapper类.在其构造函数中,我创建一个新的任务窗格,并使用

In the CreateTaskPaneWrapper method, I check a Dictionary<Document, TaskPaneWrapper> if a task pane for a document already exists. I do this because the open event fires if I try to open an already open document. If it doesn't exist, I create a new TaskPaneWrapper class. In its constructor, I create a new task pane and add it to the CustomTaskPanes collection with

Globals.ThisAddIn.CustomTaskPanes.Add(taskPane, "Title");

根据MSDN ,这会将任务窗格与当前活动的窗口相关联.

According to MSDN, this associates the task pane with the currently active window.

任务窗格关闭

Document.Close和Application.DocumentBeforeClose事件都不适合我,因为它们在用户给出确认关闭文档之前触发.因此,我在TaskPaneWrapper类中使用Microsoft.Office.Tools.Word.Document.Shutdown事件,如下所示:

Both Document.Close and Application.DocumentBeforeClose events don't suit me, because they fire before before the user gives the confirmation to close the document. So I use the Microsoft.Office.Tools.Word.Document.Shutdown event in my TaskPaneWrapper class like this:

_vstoDocument = document.GetVstoObject();
_vstoDocument.Shutdown += OnShutdown;

private void OnShutdown(object sender, EventArgs eventArgs)
{
    Globals.ThisAddIn.CustomTaskPanes.Remove(_taskPane);
    //additional shutdown logic
}

所有这些似乎都工作得很好,任务窗格已创建,绑定到相应的窗口,并已成功删除.但是,我仍然有一个问题-启动Word时,将打开一个空白文档.如果我随后在不更改空白文档的情况下打开现有文档,则会删除空白文档及其窗口,而不会触发Document.Close,Application.DocumentBeforeClose和Microsoft.Office.Tools.Word.Document.Shutdown事件.由于未调用OnShutdown且未删除空白文档的任务窗格,因此下一个文档窗口包含两个任务窗格-新的任务窗格和第一个(孤立的)任务窗格.如何删除该孤立任务窗格?访问已删除的文档或窗口引用将引发COMException(对象已删除").我是暂时使用此技巧:

All of this seems to work pretty well, the task panes are created, bound to the corresponding windows, and are successfully removed. However, I still have one problem - when I start Word, a blank document opens. If I then open an existing document without changing the blank one, the blank document and it's window is deleted without the Document.Close, Application.DocumentBeforeClose and Microsoft.Office.Tools.Word.Document.Shutdown events firing. Because OnShutdown is not called and the task pane for the blank document is not deleted, the next document window contains TWO task panes - the very new one, and the very first (orphaned) one. How can I remove this orphaned task pane? Accessing the deleted document or window reference throws a COMException ("Object was deleted"). I'm temporary using this hack:

//A property in my TaskPaneWrapper class
public bool IsWindowAlive()
{
    try
    {
        var window = _vstoDocument.ActiveWindow;
        return true;
    }
    catch (COMException)
    {
        return false;
    }
}

在CreateTaskPaneWrapper方法中,我检查所有现有包装器的此属性,并关闭该属性为false的包装器.当然,捕获异常的代价有些高昂,而且这种解决方案非常笨拙,所以我想知道,有没有更好的解决方案? 在此问题中 CustomTaskPane .Window属性被检查为null,但永远不会为我返回null.

In the CreateTaskPaneWrapper method, I check this property for all existing wrappers and shutdown the ones where the property is false. Catching an exception is somewhat expensive, of course, and this solution is pretty hacky, so I was wondering, is there a better one? In this question CustomTaskPane.Window property is checked for null, but it never returns null for me.

此外,使用当前的逻辑是否还会遇到其他问题?管理多个文档的多个任务窗格的典型方法是什么?

Also, are there any other problems I can run into using my current logic? What's the typical way of managing multiple task panes for multiple documents?

推荐答案

此答案在打开现有文档后,您无需主动清理孤立的任务窗格,而是可以在调用CreateTaskPaneWrapper之前通过从DocumentOpen事件处理程序中调用以下方法来主动清理.此代码循环遍历该外接程序的每个自定义任务窗格.如果任务窗格没有关联的窗口,则代码将从集合中删除任务窗格.

Instead of reactively cleaning up orphaned task panes after you open an existing document, you can proactively clean up by calling the following method from the DocumentOpen event handler before you call CreateTaskPaneWrapper. This code loops through each of the custom task panes that belong to the add-in. If the task pane has no associated window, the code removes the task pane from the collection.

private void RemoveOrphanedTaskPanes()
{
    for (int i = Globals.ThisAddIn.CustomTaskPanes.Count; i > 0; i--)
    {
        CustomTaskPanes ctp = Globals.ThisAddIn.CustomTaskPanes[i - 1];
        if (ctp.Window == null)
        {
            this.CustomTaskPanes.Remove(ctp);
        }
    }
}

private void Application_DocumentOpen(Word.Document Doc)
{
    RemoveOrphanedTaskPanes();
    CreateTaskPaneWrapper(document);
}

这篇关于在VSTO Word插件中为多个文档创建和管理自定义任务窗格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆