Pregunta Creación y administración de paneles de tareas personalizados para múltiples documentos en un complemento de Word VSTO


Estoy desarrollando un complemento de Word 2007-2010 utilizando VSTO en Visual Studio 2008. En mi complemento, necesito un panel de tareas personalizado para cada documento de palabra abierta. Básicamente, necesito crear un panel de tareas para cada documento, mostrar el panel de tareas correcto en la ventana del documento, hacer algo en el documento cerrado y luego quitar el panel de tareas y todas las referencias a él.

Esto es lo que he hecho hasta ahora:

Creación de panel de tareas

Creo un panel de tareas personalizado para cada documento nuevo, abierto o existente en la carga como este:

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

En el método CreateTaskPaneWrapper, verifico un Dictionary <Document, TaskPaneWrapper> si ya existe un panel de tareas para un documento. Hago esto porque el evento abierto se desencadena si intento abrir un documento ya abierto. Si no existe, creo una nueva clase TaskPaneWrapper. En su constructor, creo un nuevo panel de tareas y lo agrego a la colección CustomTaskPanes con

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

De acuerdo con MSDN, esto asocia el panel de tareas con la ventana actualmente activa.

Cierre del panel de tareas

Los eventos Document.Close y Application.DocumentBeforeClose no son adecuados para mí, ya que se activan antes de que el usuario dé la confirmación para cerrar el documento. Así que utilizo el evento Microsoft.Office.Tools.Word.Document.Shutdown en mi clase TaskPaneWrapper de esta manera:

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

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

Todo esto parece funcionar bastante bien, los paneles de tareas se crean, vinculados a las ventanas correspondientes, y se eliminan con éxito. Sin embargo, todavía tengo un problema: cuando inicio Word, se abre un documento en blanco. Si luego abro un documento existente sin cambiar el en blanco, el documento en blanco y su ventana se eliminan sin que se activen los eventos Document.Close, Application.DocumentBeforeClose y Microsoft.Office.Tools.Word.Document.Shutdown. Debido a que no se llama a OnShutdown y no se elimina el panel de tareas para el documento en blanco, la siguiente ventana del documento contiene DOS paneles de tareas, el muy nuevo y el primero (huérfano). ¿Cómo puedo eliminar este panel de tareas huérfanas? El acceso al documento eliminado o la referencia de la ventana arroja una COMException ("Objeto fue eliminado"). Soy temporal usando este truco:

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

En el método CreateTaskPaneWrapper, verifico esta propiedad para todas las envolturas existentes y apago aquellas donde la propiedad es falsa. Capturar una excepción es algo costoso, por supuesto, y esta solución es bastante hacky, así que me preguntaba, ¿hay alguna mejor? En esta pregunta La propiedad CustomTaskPane.Window está marcada como nula, pero nunca devuelve null para mí.

Además, ¿hay algún otro problema que pueda encontrar usando mi lógica actual? ¿Cuál es la forma típica de administrar múltiples paneles de tareas para múltiples documentos?


9
2018-03-21 13:40


origen


Respuestas:


Este problema se detalla en este artículo de MSDN titulado Administrar paneles de tareas en varios documentos de Word e InfoPath

Debe crear un método que elimine los CTP huérfanos (es decir, aquellos que ya no tienen ventanas adjuntas).

He seguido este artículo e implementado con éxito un administrador CustomTaskPane que elimina a los huérfanos.


5
2017-08-20 10:36



Esta respuesta en MSDN

En lugar de limpiar de forma reactiva los paneles de tareas huérfanas después de abrir un documento existente, puede realizar una limpieza proactiva llamando al siguiente método desde el controlador de eventos DocumentOpen antes de llamar a CreateTaskPaneWrapper. Este código recorre cada uno de los paneles de tareas personalizados que pertenecen al complemento. Si el panel de tareas no tiene una ventana asociada, el código elimina el panel de tareas de la colección.

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

3
2018-01-03 22:20



Algunas cosas para probar ::

  1. Quizás pueda verificar "Word.Application.Documents.Count" en DocumentNew- y DocumentOpen-Event para rastrear el documento abierto real.

  2. Para saber si un documento ya está abierto (quizás relevante para volver a abrir el documento activo), puede usar un diccionario de documentos abiertos. La clave puede ser el nombre único del documento.

  3. En lugar de su método IsWindowAlive (), puede atrapar el Evento Dispuesto de la siguiente manera

_vstoDocument.Disposed += _vstoDocument_Disposed;

        void _vstoDocument_Disposed(object sender, EventArgs e)
        {
            //Remove from dictionary of open documents 
        }

0
2018-06-10 09:40