Question

J'ai pu accéder à un signet dans mon document Word à l'aide de ce code:

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

Maintenant, je veux insérer un paragraphe et un tableau après ce signet. Comment je fais ça? (un exemple de code serait apprécié)

Était-ce utile?

La solution

Code

Une fois le signet créé, vous pouvez accéder à son élément parent et ajouter les autres éléments après.

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

Le code ci-dessus devrait le faire. Cependant, je vais expliquer certaines circonstances particulières.

Sachez qu'il tentera les insertions après l'élément parent du signet. Quel comportement attendez-vous si votre signet fait partie d'un paragraphe à l'intérieur d'un tableau? Devrait-il ajouter le nouveau paragraphe et le tableau juste après, dans ce tableau? Ou devrait-il le faire après cette table?

Vous vous demandez peut-être pourquoi les questions ci-dessus sont importantes. Tout dépend de l'endroit où l'insertion aura lieu. Si le parent du signet est dans une table, le code ci-dessus tente actuellement de placer une table dans une table. C'est bien, mais une erreur peut survenir en raison d'une structure OpenXml non valide. La raison en est que si la table insérée était le dernier élément de la table TableCell de la table d'origine, un élément de paragraphe devait être ajouté après la balise de fermeture TableCell. Vous découvrirez rapidement ce problème s’il se produisait une fois que vous avez tenté d’ouvrir le document dans MS Word.

La solution consiste à déterminer si vous effectuez effectivement l'insertion dans un tableau.

Pour ce faire, nous pouvons ajouter au code ci-dessus (après la variable parent):

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

Cela devrait empêcher l’erreur de se produire et vous donner un OpenXml valide. L’idée de la boucle while peut être utilisée si vous avez répondu "oui". à ma question précédente et je voulais effectuer l’insertion après la table parent plutôt que dans la table comme le ferait le code ci-dessus. Si tel est le cas, le problème ci-dessus ne serait plus un problème et vous pouvez remplacer cette boucle et ce booléen par le texte suivant:

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

Ceci permet de réaffecter le parent jusqu'à ce qu'il soit l'élément principal contenant au niveau du corps. Ainsi, si le signet se trouvait dans un paragraphe figurant dans un tableau, il passerait de paragraphe en tableau à cellule de tableau à tableau en passant à tableau et s'arrêterait là puisque le parent du tableau est le corps. À ce stade, parent = élément de table et nous pouvons insérer après.

Cela devrait couvrir différentes approches, selon votre intention initiale. Faites-moi savoir si vous avez besoin d'éclaircissements après l'avoir essayé.

Réflecteur de document

Vous vous demandez peut-être comment j'ai déterminé les valeurs GridColumn.Width . J'ai créé un tableau et utilisé l'outil Document Reflector pour le récupérer. Lorsque vous avez installé le Kit de développement Open Xml SDK, les outils de productivité (si vous les avez installés) se trouvent dans C: \ Program Files \ Format XML Open SDK \ V2.0 \ tools (ou similaire).

Le meilleur moyen de connaître le fonctionnement du format * .docx (ou de tout document au format Open Xml) consiste à ouvrir un fichier existant avec l'outil Document Reflector. Naviguez dans la partie du document et localisez les éléments à répliquer. L'outil vous indique le code utilisé pour générer le document entier. C'est un code que vous pouvez copier / coller dans votre application pour générer des résultats similaires. Vous pouvez généralement ignorer tous les ID de référence. vous devrez jeter un coup d'œil et l'essayer pour vous faire une idée.

Comme je l'ai mentionné, le code de la table ci-dessus a été adapté à partir d'un exemple de document. J'ai ajouté un simple tableau à un docx, puis je l'ai ouvert dans l'outil et j'ai copié le code généré par l'outil (j'ai supprimé quelques extras pour le nettoyer). Cela m'a donné un échantillon de travail pour ajouter un tableau.

Cela est particulièrement utile lorsque vous souhaitez savoir comment écrire du code qui génère quelque chose, tel que des tableaux mis en forme et des paragraphes avec des styles, etc.

Consultez ce lien pour des captures d'écran et des informations sur les autres outils inclus dans le SDK: Une introduction à Open XML SDK 2.0 .

Extraits de code

Les extraits de code pour Open Xml pourraient également vous intéresser. Pour obtenir une liste des extraits, consultez cet article de blog . Vous pouvez les télécharger ici: Bureau 2007 Exemple de système: Extraits de code du SDK 2.0 au format Open XML pour Visual Studio 2008 .

Une fois installés, ajoutez-les à partir de Outils | Menu Gestionnaire d'extraits de code. Sélectionnez C # pour la langue, cliquez sur le bouton Ajouter, puis accédez à Dossier perso \ Visual Studio 2008 \ Extraits de code \ Visual C # \ Open XML SDK 2.0 pour Microsoft Office pour les ajouter. Dans votre code, cliquez avec le bouton droit de la souris et sélectionnez "Insérer un extrait". et sélectionnez celui que vous voulez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top