Guardar controles dinámicos en documentos de Office

Los controles que se agregan en tiempo de ejecución no se conservan al guardar y cerrar el documento o el libro. El comportamiento exacto es diferente para los controles host y para los controles de Windows Forms. En ambos casos, puede agregar código a la solución para volver a crear los controles cuando el usuario vuelva a abrir el documento.

Los controles que se agregan a los documentos en tiempo de ejecución se denominan controles dinámicos. Para obtener más información sobre los controles dinámicos, vea Agregar controles a documentos de Office en tiempo de ejecución.

Se aplica a: la información de este tema se aplica a los proyectos de nivel de documento y los proyectos de nivel de aplicación para las siguientes aplicaciones: Excel 2007 y Excel 2010; Word 2007 y Word 2010. Para obtener más información, vea Características disponibles por aplicación y tipo de proyecto de Office.

Guardar controles host en el documento

Cuando un documento se guarda y, a continuación, se cierra, todos los controles host dinámicos se quitan del documento. Únicamente se conservan los objetos de Office nativos subyacentes. Por ejemplo, un control host Microsoft.Office.Tools.Excel.ListObject se convierte en Microsoft.Office.Interop.Excel.ListObject. Los objetos de Office nativos no están conectados a los eventos del control host y no disponen de la funcionalidad de enlace de datos del control host.

En la tabla siguiente se muestra una lista con los objetos de Office nativos que se conservan en el documento para cada tipo de control host.

Tipo de control host

Tipo de objeto de Office nativo

Microsoft.Office.Tools.Excel.Chart

Microsoft.Office.Interop.Excel.Chart

Microsoft.Office.Tools.Excel.ListObject

Microsoft.Office.Interop.Excel.ListObject

Microsoft.Office.Tools.Excel.NamedRange

Microsoft.Office.Interop.Excel.Range

Microsoft.Office.Tools.Word.Bookmark

Microsoft.Office.Interop.Word.Bookmark

Microsoft.Office.Tools.Word.BuildingBlockGalleryContentControl

Microsoft.Office.Tools.Word.ComboBoxContentControl

Microsoft.Office.Tools.Word.ContentControl

Microsoft.Office.Tools.Word.DatePickerContentControl

Microsoft.Office.Tools.Word.DropDownListContentControl

Microsoft.Office.Tools.Word.GroupContentControl

Microsoft.Office.Tools.Word.PictureContentControl

Microsoft.Office.Tools.Word.PlainTextContentControl

Microsoft.Office.Tools.Word.RichTextContentControl

Microsoft.Office.Interop.Word.ContentControl

Volver a crear controles host dinámicos al abrir documentos

Puede volver a crear controles host dinámicos en lugar de los controles nativos existentes cada vez que un usuario abra el documento. La creación de controles host de esta manera al abrir un documento simula la experiencia que al usuario le cabría esperar.

Para volver a crear un control host de Word o un control host de Excel Microsoft.Office.Tools.Excel.NamedRange o Microsoft.Office.Tools.Excel.ListObject, utilice un método Add<clase de control> de un objeto Microsoft.Office.Tools.Excel.ControlCollection o Microsoft.Office.Tools.Word.ControlCollection. Utilice un método que tenga un parámetro para el objeto nativo de Office.

Por ejemplo, si desea crear un control host Microsoft.Office.Tools.Excel.ListObject a partir de un objeto Microsoft.Office.Interop.Excel.ListObject nativo existente cuando se abra el documento, utilice el método AddListObject(ListObject) y pase el objeto Microsoft.Office.Interop.Excel.ListObject existente. En el siguiente ejemplo de código, se muestra esto en un proyecto de nivel de documento para Excel. El código vuelve a crear un control Microsoft.Office.Tools.Excel.ListObject dinámico que se basa en un control Microsoft.Office.Interop.Excel.ListObject existente denominado MyListObject de la clase Sheet1.

Private vstoListObject As Microsoft.Office.Tools.Excel.ListObject
Private Const DISP_E_BADINDEX As Integer = CInt(&H8002000B)

Private Sub Sheet1_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
    Dim nativeListObject As Excel.ListObject = Nothing

    Try
        nativeListObject = Me.ListObjects("MyListObject")
    Catch ex As System.Runtime.InteropServices.COMException
        ' "MyListObject" does not exist.
        If ex.ErrorCode <> DISP_E_BADINDEX Then
            Throw
        End If
    End Try

    If nativeListObject IsNot Nothing Then
        vstoListObject = Me.Controls.AddListObject(nativeListObject)
    End If
End Sub
private Microsoft.Office.Tools.Excel.ListObject vstoListObject;
private const int DISP_E_BADINDEX = unchecked((int)0x8002000B);

private void Sheet1_Startup(object sender, System.EventArgs e)
{
    Excel.ListObject nativeListObject = null;

    try
    {
        nativeListObject = this.ListObjects.get_Item("MyListObject");
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        // "MyListObject" does not exist.
        if (ex.ErrorCode != DISP_E_BADINDEX)
            throw;
    }

    if (nativeListObject != null)
    {
        vstoListObject = this.Controls.AddListObject(nativeListObject);
    }
}

Volver a crear gráficos

Para volver a crear un control host Microsoft.Office.Tools.Excel.Chart, antes debe eliminar el objeto Microsoft.Office.Interop.Excel.Chart nativo y, a continuación, volver a crear Microsoft.Office.Tools.Excel.Chart mediante el método AddChart(Range, String) o AddChart(Double, Double, Double, Double, String). No existe ningún método Add<clase de control> que permita crear un nuevo objeto Microsoft.Office.Tools.Excel.Chart basado en un objeto Microsoft.Office.Interop.Excel.Chart ya existente.

Si no elimina antes el objeto Microsoft.Office.Interop.Excel.Chart nativo, se creará un segundo gráfico duplicado al volver a crear el objeto Microsoft.Office.Tools.Excel.Chart.

Guardar controles de formularios Windows Forms en documentos

Cuando se guarda y, a continuación, se cierra un documento, el Motor en tiempo de ejecución de Microsoft Visual Studio Tools para Office quita automáticamente del documento todos los controles de Windows Forms creados dinámicamente. Sin embargo, el comportamiento es diferente para los proyectos en el nivel del documento y en el nivel de la aplicación.

En las personalizaciones en el nivel del documento, los controles y sus contenedores de ActiveX subyacentes (que se utilizan para hospedar los controles en el documento) se quitan la próxima vez que se abre el documento. No hay ninguna indicación de que los controles hayan estado allí jamás.

En los complementos en el nivel de la aplicación, los controles se quitan, pero los contenedores de ActiveX permanecen en el documento. La próxima vez que el usuario abre el documento, los contenedores de ActiveX están visibles. En Excel, los contenedores de ActiveX muestran imágenes de los controles como aparecían la última vez que se guardó el documento. En Word, los contenedores de ActiveX no están visibles a menos que el usuario haga clic en ellos, en cuyo caso muestran una línea de puntos que representa el borde de los controles. Hay varias maneras de quitar los contenedores de ActiveX. Para obtener más información, vea Quitar los contenedores de ActiveX en un complemento.

Volver a crear controles de formularios Windows Forms al abrir documentos

Puede volver a crear los controles de formularios Windows Forms eliminados cuando el usuario vuelve a abrir el documento. Para ello, la solución debe realizar las tareas siguientes:

  1. Guardar la información sobre el tamaño, ubicación y estado de los controles al guardar o cerrar el documento. En una personalización en el nivel del documento, puede guardar estos datos en la memoria caché de datos del documento. En un complemento en el nivel de la aplicación, puede guardar estos datos en un elemento XML personalizado del documento.

  2. Volver a crear los controles en un evento que se provoca al abrir el documento. En los proyectos en el nivel del documento, puede hacerlo en los controladores de eventos Sheetn_Startup o ThisDocument_Startup. En los proyectos en el nivel de la aplicación, puede hacerlo en los controladores de los eventos DocumentOpen o WorkbookOpen.

Quitar los contenedores de ActiveX en un complemento

Al agregar controles de Windows Forms dinámicos a los documentos utilizando un complemento, puede evitar que los contenedores de ActiveX de los controles aparezcan en el documento la próxima vez que se abra, de las maneras siguientes.

Quitar los contenedores de ActiveX al abrir el documento

Para quitar todos los contenedores de ActiveX, llame al método GetVstoObject a fin de generar un elemento host para el objeto Microsoft.Office.Interop.Word.Document o Microsoft.Office.Interop.Excel.Workbook que representa el documento que se acaba de abrir. Por ejemplo, para quitar todos los contenedores de ActiveX de un documento de Word, puede llamar al método GetVstoObject a fin de generar un elemento host para el objeto Document que se pasa al controlador del evento DocumentOpen.

Este procedimiento resulta útil si se tiene al certeza de que el documento sólo se abrirá en equipos donde esté instalado el complemento. Si existe la posibilidad de que el documento se pase a otros usuarios que no tengan instalado el complemento, puede ser conveniente quitar los controles antes de cerrar documento.

En el ejemplo de código siguiente se muestra cómo llamar al método GetVstoObject al abrir el documento.

Private Sub Application_DocumentOpen_ClearActiveXWrappers( _
    ByVal Doc As Word.Document) Handles Application.DocumentOpen

    ' Use the following line of code in projects that target the .NET Framework 4.
    Dim vstoDocument As Document = Globals.Factory.GetVstoObject(Doc)

    ' In projects that target the .NET Framework 3.5, use the following line of code.
    ' Dim vstoDocument As Microsoft.Office.Tools.Word.Document = Doc.GetVstoObject()
End Sub
private void Application_DocumentOpen_ClearActiveXWrappers(Word.Document Doc)
{
    // Use the following line of code in projects that target the .NET Framework 4.
    Microsoft.Office.Tools.Word.Document vstoDocument = Globals.Factory.GetVstoObject(Doc);

    // In projects that target the .NET Framework 3.5, use the following line of code.
    // Microsoft.Office.Tools.Word.Document vstoDocument = Doc.GetVstoObject();
}

Aunque el método GetVstoObject se utiliza principalmente para generar un nuevo elemento host en tiempo de ejecución, también borra todos los contenedores de ActiveX del documento la primera vez que se le llama para un documento concreto. Para obtener más información sobre cómo utilizar el método GetVstoObject, vea Ampliar documentos de Word y libros de Excel en complementos en el nivel de la aplicación en tiempo de ejecución.

Tenga en cuenta que si el complemento crea controles dinámicos al abrir el documento, llamará al método GetVstoObject como parte del proceso para crear los controles. En este escenario, no es necesario agregar una llamada independiente al método GetVstoObject para quitar los contenedores de ActiveX.

Quitar los controles dinámicos antes de cerrar el documento

El complemento puede quitar explícitamente todos los controles dinámicos del documento antes de cerrarlo. Este procedimiento resulta útil para los documentos que se podrían pasar a otros usuarios que no tengan el complemento instalado.

En el ejemplo de código siguiente se muestra cómo quitar todos los controles de Windows Forms de un documento de Word al cerrarlo.

Private Sub Application_DocumentBeforeClose(ByVal Doc As Word.Document, _
    ByRef Cancel As Boolean) Handles Application.DocumentBeforeClose

    ' Use the following line of code in projects that target the .NET Framework 4.
    Dim isExtended As Boolean = Globals.Factory.HasVstoObject(Doc)

    ' In projects that target the .NET Framework 3.5, use the following line of code.
    ' Dim isExtended As Boolean = Doc.HasVstoObject()

    If isExtended Then
        ' Use the following line of code in projects that target the .NET Framework 4.
        Dim vstoDocument As Document = Globals.Factory.GetVstoObject(Doc)

        ' In projects that target the .NET Framework 3.5, use the following line of code.
        ' Dim vstoDocument As Document = Doc.GetVstoObject()

        Dim controlsToRemove As System.Collections.ArrayList = _
            New System.Collections.ArrayList()

        ' Get all of the Windows Forms controls.
        For Each control As Object In vstoDocument.Controls
            If TypeOf control Is System.Windows.Forms.Control Then
                controlsToRemove.Add(control)
            End If
        Next

        ' Remove all of the Windows Forms controls from the document.
        For Each control As Object In controlsToRemove
            vstoDocument.Controls.Remove(control)
        Next
    End If
End Sub
void Application_DocumentBeforeClose(Word.Document Doc, ref bool Cancel)
{
    // Use the following line of code in projects that target the .NET Framework 4.
    bool isExtended = Globals.Factory.HasVstoObject(Doc);

    // In projects that target the .NET Framework 3.5, use the following line of code.
    // bool isExtended = Doc.HasVstoObject();

    if (isExtended)
    {
        // Use the following line of code in projects that target the .NET Framework 4.
        Microsoft.Office.Tools.Word.Document vstoDocument = Globals.Factory.GetVstoObject(Doc);

        // In projects that target the .NET Framework 3.5, use the following line of code.
        // Microsoft.Office.Tools.Word.Document vstoDocument = Doc.GetVstoObject();

        System.Collections.ArrayList controlsToRemove = 
            new System.Collections.ArrayList();

        // Get all of the Windows Forms controls.
        foreach (object control in vstoDocument.Controls)
        {
            if (control is System.Windows.Forms.Control)
            {
                controlsToRemove.Add(control);
            }
        }

        // Remove all of the Windows Forms controls from the document.
        foreach (object control in controlsToRemove)
        {
            vstoDocument.Controls.Remove(control);
        }
    }
}

Vea también

Conceptos

Agregar controles a documentos de Office en tiempo de ejecución

Métodos auxiliares para controles host

Métodos auxiliares para controles de formularios Windows Forms