Domanda

Sono stato in grado di accedere a un segnalibro nel mio documento Word utilizzando questo codice:

var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>()
                              where bm.Name == "BookmarkName"
                              select bm;

Ora voglio inserire un paragrafo e una tabella dopo questo segnalibro. Come lo faccio? (sarebbe apprezzato il codice di esempio)

È stato utile?

Soluzione

Codice

Una volta che hai il segnalibro puoi accedere al suo elemento genitore e aggiungere gli altri elementi dopo di esso.

using (WordprocessingDocument document = WordprocessingDocument.Open(@"C:\Path\filename.docx", true))
{
    var mainPart = document.MainDocumentPart;
    var res = from bm in mainPart.Document.Body.Descendants<BookmarkStart>()
              where bm.Name == "BookmarkName"
              select bm;
    var bookmark = res.SingleOrDefault();
    if (bookmark != null)
    {
        var parent = bookmark.Parent;   // bookmark's parent element

        // simple paragraph in one declaration
        //Paragraph newParagraph = new Paragraph(new Run(new Text("Hello, World!")));

        // build paragraph piece by piece
        Text text = new Text("Hello, World!");
        Run run = new Run(new RunProperties(new Bold()));
        run.Append(text);
        Paragraph newParagraph = new Paragraph(run);

        // insert after bookmark parent
        parent.InsertAfterSelf(newParagraph);

        var table = new Table(
        new TableProperties(
            new TableStyle() { Val = "TableGrid" },
            new TableWidth() { Width = 0, Type = TableWidthUnitValues.Auto }
            ),
            new TableGrid(
                new GridColumn() { Width = (UInt32Value)1018U },
                new GridColumn() { Width = (UInt32Value)3544U }),
        new TableRow(
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("Category Name"))
                )),
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 4788, Type = TableWidthUnitValues.Dxa }),
                new Paragraph(
                    new Run(
                        new Text("Value"))
                ))
        ),
        new TableRow(
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("C1"))
                )),
            new TableCell(
                new TableCellProperties(
                    new TableCellWidth() { Width = 0, Type = TableWidthUnitValues.Auto }),
                new Paragraph(
                    new Run(
                        new Text("V1"))
                ))
        ));

        // insert after new paragraph
        newParagraph.InsertAfterSelf(table);
    }

    // close saves all parts and closes the document
    document.Close();
}

Il codice sopra dovrebbe farlo. Tuttavia, spiegherò alcune circostanze speciali.

Ricorda che tenterà l'inserimento dopo l'elemento genitore del segnalibro. Che comportamento ti aspetti se il tuo segnalibro fa parte di un paragrafo all'interno di una tabella? Dovrebbe aggiungere il nuovo paragrafo e la tabella subito dopo, all'interno di quella tabella? O dovrebbe farlo dopo quella tabella?

Potresti chiederti perché le domande precedenti contano. Tutto dipende da dove avverrà l'inserimento. Se il genitore del segnalibro si trova in una tabella, attualmente il codice sopra tenterebbe di posizionare una tabella all'interno di una tabella. Va bene, tuttavia potrebbe verificarsi un errore a causa di una struttura OpenXml non valida. Il motivo è che se la tabella inserita era l'ultimo elemento nel TableCell della tabella originale, è necessario aggiungere un elemento Paragrafo dopo il tag TableCell di chiusura. Scopriresti prontamente questo problema se si verificasse dopo aver tentato di aprire il documento in MS Word.

La soluzione è determinare se stai effettivamente eseguendo l'inserimento all'interno di una tabella.

Per fare ciò, possiamo aggiungere al codice sopra (dopo il genitore var):

    var parent = bookmark.Parent;   // bookmark's parent element

    // loop till we get the containing element in case bookmark is inside a table etc.
    // keep checking the element's parent and update it till we reach the Body
    var tempParent = bookmark.Parent;
    bool isInTable = false;
    while (tempParent.Parent != mainPart.Document.Body)
    {
        tempParent = tempParent.Parent;
        if (tempParent is Table && !isInTable)
            isInTable = true;
    }

    // ... 

    newParagraph.InsertAfterSelf(table);  // from above sample
    // if bookmark is in a table, add a paragraph after table
    if (isInTable)
        table.InsertAfterSelf(new Paragraph());

Ciò dovrebbe impedire il verificarsi dell'errore e fornire OpenXml valido. L'idea del ciclo while può essere utilizzata se hai risposto " sì " alla mia domanda precedente e volevo eseguire l'inserimento dopo la tabella padre anziché all'interno della tabella come farebbe il codice sopra. In tal caso, il problema sopra riportato non sarebbe più un problema e puoi sostituire quel loop e booleano con il seguente:

    var parent = bookmark.Parent;   // bookmark's parent element
    while (parent.Parent != mainPart.Document.Body)
    {
        parent = parent.Parent;
    }

Questo continua a riassegnare il genitore fino a quando non è l'elemento principale a livello di Corpo. Quindi, se il segnalibro si trovava in un paragrafo che si trovava in una tabella, passerebbe da Paragrafo a TableCell a TableRow a Table e si fermerebbe lì poiché il padre della tabella è il corpo. A quel punto parent = elemento Table e possiamo inserirlo dopo.

Questo dovrebbe coprire alcuni approcci diversi, a seconda del tuo intento originale. Fammi sapere se hai bisogno di chiarimenti dopo averlo provato.

Document Reflector

Potresti chiederti come ho determinato i valori GridColumn.Width . Ho creato un tavolo e ho usato lo strumento Document Reflector per ottenerlo. Quando hai installato Open Xml SDK, gli strumenti di produttività (se li hai installati) si trovavano in C: \ Programmi \ Open XML Format SDK \ V2.0 \ tools (o simili).

Il modo migliore per imparare come funziona il formato * .docx (o qualsiasi documento in formato Open Xml) è aprire un file esistente con lo strumento Document Reflector. Passare alla parte del documento e individuare gli elementi che si desidera replicare. Lo strumento mostra il codice effettivo utilizzato per generare l'intero documento. Questo è il codice che puoi copiare / incollare nella tua applicazione per generare risultati simili. Di solito è possibile ignorare tutti gli ID di riferimento; dovresti dare un'occhiata e provarlo per farti un'idea.

Come ho già detto, il codice della tabella sopra è stato adattato da un documento di esempio. Ho aggiunto una semplice tabella a un docx, quindi l'ho aperta nello strumento e ho copiato il codice generato dallo strumento (ho rimosso alcuni extra per ripulirlo). Questo mi ha dato un esempio funzionante per aggiungere una tabella.

È particolarmente utile quando vuoi sapere come scrivere codice che genera qualcosa, come tabelle formattate e paragrafi con stili ecc.

Dai un'occhiata a questo link per schermate e informazioni sugli altri strumenti inclusi nell'SDK: Un'introduzione a Apri XML SDK 2.0 .

Snippet di codice

Potresti anche essere interessato ai frammenti di codice per Open Xml. Per un elenco di frammenti, seleziona questo post sul blog . Puoi scaricarli da qui: 2007 Office Esempio di sistema: frammenti di codice SDK 2.0 in formato XML aperto per Visual Studio 2008 .

Una volta installato, li aggiungeresti da Strumenti | Menu Gestione snippet di codice. Seleziona C # per la lingua, fai clic sul pulsante Aggiungi e vai a Cartella personale \ Visual Studio 2008 \ Snippet di codice \ Visual C # \ Open XML SDK 2.0 per Microsoft Office per aggiungerli. Dal tuo codice, fai clic con il pulsante destro del mouse e seleziona " Inserisci snippet " e seleziona quello che desideri.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top