Введите OpenXmlElement после того, как закладка слова в Откроет XML SDK

Один главный недостаток использования чего-то как Ваш DictObj является Вами или должен ограничить допустимые ключи, или у Вас не может быть методов на Вашем DictObj такой как .keys(), .values(), .items(), и т.д.

6
задан akosch 23 October 2009 в 10:10
поделиться

1 ответ

Код

Если у вас есть закладка, вы можете получить доступ к ее родительскому элементу и добавить другие элементы после нее.

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

Приведенный выше код должен сделать это. Однако я объясню некоторые особые обстоятельства.

Имейте в виду, что он будет пытаться вставить после родительского элемента закладки. Какого поведения вы ожидаете, если ваша закладка окажется частью абзаца внутри таблицы? Следует ли добавить новый абзац и таблицу сразу после него в эту таблицу? Или он должен делать это после этой таблицы?

Вы можете спросить, почему вышеупомянутые вопросы имеют значение. Все зависит от того, где будет происходить прошивка. Если родительская закладка находится в таблице, в настоящее время приведенный выше код попытается поместить таблицу в таблицу. Это нормально, однако из-за неправильной структуры OpenXml может возникнуть ошибка. Причина в том, что если вставленная таблица была последним элементом в TableCell исходной таблицы, после закрывающего тега TableCell должен быть добавлен элемент Paragraph. Вы бы сразу обнаружили эту проблему, если бы она возникла при попытке открыть документ в MS Word.

Решение состоит в том, чтобы определить, действительно ли вы выполняете вставку в таблице.

Для этого мы можем добавить в приведенный выше код (после родительской переменной):

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

Это должно предотвратить возникновение ошибки и предоставить вам действующий OpenXml. Идею цикла while можно использовать, если вы ответили «да» на мой предыдущий вопрос и хотите выполнить вставку после родительской таблицы, а не внутри таблицы, как в приведенном выше коде. Если это так, вышеупомянутая проблема больше не будет проблемой, и вы можете заменить этот цикл и логическое значение следующим:

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

Это продолжает переназначать родителя, пока он не станет основным содержащим элементом на уровне Body. Таким образом, если закладка была в абзаце, который был в таблице, она перешла бы от Paragraph к TableCell, затем TableRow к Table и остановилась на этом, поскольку родительский элемент Table - это Body. В этот момент элемент parent = Table, и мы можем вставить после него.

Это должно охватывать несколько различных подходов, в зависимости от вашего первоначального намерения. Дайте мне знать, если вам понадобятся какие-либо разъяснения после того, как вы попробуете его.

Document Reflector

Вам может быть интересно, как я определил значения GridColumn.Width . Я сделал таблицу и использовал инструмент Document Reflector, чтобы получить ее. Когда вы установили Open Xml SDK, инструменты повышения производительности (если вы их установили) будут находиться в C: \ Program Files \ Open XML Format SDK \ V2.0 \ tools (или аналогичном).

Лучший способ узнать, как Формат * .docx (или любой документ в формате Open Xml) работает для открытия существующего файла с помощью инструмента Document Reflector. Перемещайтесь по части документа и найдите элементы, которые хотите воспроизвести. Инструмент показывает вам фактический код, используемый для создания всего документа. Это код, который вы можете скопировать / вставить в свое приложение для получения аналогичных результатов. Обычно вы можете игнорировать все ссылочные идентификаторы; вам придется взглянуть и попробовать его, чтобы почувствовать это.

Как я уже упоминал, приведенный выше код таблицы был адаптирован из образца документа. Я добавил простую таблицу в docx, затем открыл ее в инструменте и скопировал код, сгенерированный инструментом (я удалил некоторые дополнения, чтобы очистить его). Это дало мне рабочий образец для добавления таблицы.

Это особенно полезно, когда вы хотите знать, как написать код, который что-то генерирует, например отформатированные таблицы и абзацы со стилями и т. Д.

Взгляните на эту ссылку для получения снимков экрана и информации о других инструментах, включенных в SDK: Введение в Open XML SDK 2.0 .

Фрагменты кода

Возможно, вас также заинтересуют фрагменты кода для Open Xml. Список фрагментов можно найти в этом сообщении в блоге . Вы можете скачать их отсюда: Образец 2007 системы Office: фрагменты кода SDK 2.0 формата Open XML для Visual Studio 2008 .

После установки вы можете добавить их из Инструменты | Меню диспетчера фрагментов кода. Выберите C # в качестве языка, нажмите кнопку Добавить, и перейдите к PersonalFolder \ Visual Studio 2008 \ Code Snippets \ Visual C # \ Open XML SDK 2.0 для Microsoft Office , чтобы добавить их. В своем коде щелкните правой кнопкой мыши, выберите «Вставить фрагмент» и выберите нужный.

28
ответ дан 8 December 2019 в 03:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: