Microsoft office interop word как подключить

Обновлено: 04.07.2024

Пять предметов
Приложение: представляет само приложение Microsoft Word
Document: представляет документ Word
Selection: представляет текущую выделенную область (выделенную), представляет точку курсора, когда область не выделена
Закладки: Закладки
Range: представляет область, похожую на Selection, но обычно не видимую

Диаграмма наследования объектной модели Word

Это видно из рисунка выше:
 Приложение - это базовый класс Document and Selection. Через свойства и методы приложения, мы можем контролировать среду Word.
 Документ представляет собой документ Word. Когда вы создаете новый документ Word или открываете существующий документ Word, вы создаете объект Document, который добавляется в коллекцию документов Word. Документ с фокусом называется
ActiveDocument, вы можете использовать свойство ActiveDocument объекта Application
Получить текущий объект документа
 Выбор представляет текущую выбранную область
region Область в документе объекта Range, которая имеет следующие характеристики
tains Содержит начальную и конечную позиции
 Он содержит только точку вставки, фрагмент текста или весь документ
contains Содержит пробелы, вкладки и знаки абзаца
may Это может быть выбранная в данный момент область или не выбранная в данный момент область
 Создан динамически
 Когда вы вставляете текст в конец диапазона, он расширяет диапазон
object Объект закладки также представляет область, обычно для создания документа используется закладка
, имеет следующие характеристики
Object Объекту закладки можно присвоить имя
 Сохранено вместе с документом, и оно существует, даже если документ закрыт
usually Обычно он скрыт, но его также можно настроить для отображения с помощью кода

1.2 Методы применения объекта
 CheckSpelling

// Prompt to save changes. saveChanges = Word.WdSaveOptions.wdPromptToSaveChanges; originalFormat = Type.Missing; routeDocument = Type.Missing;
ThisApplication.Quit( ref saveChanges,
ref originalFormat, ref routeDocument);

// Quit without saving changes. saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges; originalFormat = Type.Missing; routeDocument = Type.Missing;
ThisApplication.Quit( ref saveChanges,
ref originalFormat, ref routeDocument);

  1. The Document Object
    Использование объекта Document позволяет работать с документом и из-за документов.
    С существованием Collection вы можете управлять всеми открытыми документами.
    2.1 Document Object Collections
    Документ может содержать следующие типы объектов:
     Characters
     Words
     Sentences
     Paragraphs
     Sections
     Headers/Footers

2.3 Открывать, закрывать и создавать новые документы
 Add

ThisApplication.Documents.Open(ref filename, ref confirmConversions, ref readOnly, ref addToRecentFiles, ref passwordDocument, ref passwordTemplate, ref revert, ref writePasswordDocument, ref writePasswordTemplate, ref format, ref encoding, ref visible, ref openConflictDocument, ref openAndRepair , ref documentDirection, ref noEncodingDialog);
 Save
// Сохранить все документы
Object noPrompt = true;
Object originalFormat = Type.Missing;
ThisApplication.Documents.Save(ref noPrompt, ref originalFormat);

// Сохраняем документ с указанным именем
Object file = “MyNewDocument.doc”;
ThisApplication.Documents.get_Item(ref file).Save();

ThisDocument.SaveAs(ref fileName, ref fileFormat, ref lockComments, ref password, ref addToRecentFiles, ref writePassword, ref readOnlyRecommended, ref embedTrueTypeFonts, ref saveNativePictureFormat, ref saveFormsData, ref saveAsAOCELetter, ref encoding, ref insertLineBreaks, ref allowSubstitutions, ref lineEnding, ref addBiDiMarks);

 Close
// Закрыть все документы
Object saveChanges = Word.WdSaveOptions.wdSaveChanges;
Object originalFormat = Type.Missing; Object routeDocument = Type.Missing;
ThisApplication.Documents.Close(ref saveChanges,
ref originalFormat, ref routeDocument);

// закрываем активный документ
Object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
Object originalFormat = Type.Missing; Object routeDocument = Type.Missing;
ThisDocument.Close( ref saveChanges,
ref originalFormat, ref routeDocument);

// Close MyNewDocument and save changes without prompting. Object name = “MyNewDocument.doc”; saveChanges = Word.WdSaveOptions.wdSaveChanges; originalFormat = Type.Missing; routeDocument = Type.Missing;

Word.Document doc = ThisApplication.Documents.get_Item(ref name); ThisDocument.Close( ref saveChanges,
ref originalFormat, ref routeDocument);

  1. The Selection Object
    Объект Selection представляет текущую выделенную область. В приложении Word, если вы хотите выделить часть символов жирным шрифтом, вы должны сначала выбрать часть текста, а затем применить стиль. То же самое верно в коде, вы должны сначала определить область выбора, а затем работать. Вы можете использовать объект «Выделение» для выбора, форматирования, обработки, добавления текста и т. Д. В документе.
    Объект Selection всегда существует. Если в настоящий момент ничего не выделено, он представляет точку вставки. Поэтому очень важно знать, что в нем содержится, прежде чем приступить к работе с Seleciton.
    Советы. Объект Selection и объект Range имеют много одинаковых членов, разница между ними заключается в том, что объект Selection ссылается на область, которая фактически находится в графическом интерфейсе, а область, представленная объектом Range, не является. Видимый (конечно, это можно сделать видимым с помощью вызова методов)

3.2 Navigating and Selecting Text
Чтобы определить, что выбрано, вы также можете использовать следующий метод.

3.2.1 Home and End Key Method
При использовании Word мы знаем, что нажатие клавиши HOME на клавиатуре переместит курсор в начало строки, в которой находится курсор, а нажатие клавиши END переместит курсор в конец строки. В коде вы можете использовать аналоговую печать
ключевой метод изменит выбор. Пожалуйста, посмотрите на следующие две функции:
HomeKey ([Unit], [Extend]): имитация нажатия клавиши HOME
EndKey ([Unit], [Extend]): имитировать нажатие клавиши END
В приведенных выше двух функциях параметр Unit имеет следующие необязательные значения (тип wdUnit):
 Wdline перемещается в начало или конец строки (по умолчанию)
 WdStory перемещается в начало или конец документа
 WdColumn перемещается в начало или конец столбца (только для таблиц)  WdRow перемещается в начало или конец строки (только для таблиц)
Необязательное значение параметра Extend (тип WdMovementType):
selection выбор мобильного WdMove
 WdExtend расширенный выбор. Например: рассмотрим сценарий, в котором в настоящий момент выбрана строка, а затем вызывается метод HomeKey с параметрами wdStory и wdExtend, после чего строка не будет включена в новый объект выбора. В том же случае, если вызывается метод EndKey, строка будет включена в В новом объекте выбора.

// Select the 3 words to the right of the insertion point. unit = Word.WdUnits.wdWord; count = 3;
extend = Word.WdMovementType.wdExtend;
ThisApplication.Selection.MoveRight(ref unit, ref count, ref extend);

3.2.3 Move Method
Использование метода Move изменит указанный диапазон или выбор. Следующий пример переместит точку вставки перед третьим словом

// Use the Move method to move 3 words.
Obiect unit = Word.WdUnits.wdWord;
Object count = 3;
ThisApplication.Selection.Move(ref unit, ref count);

3.2.4 Inserting Text
Самый простой способ вставить текст в документ - это использовать метод TypeText объекта Selection. Поведение метода TypeText определяется выбором пользователя. В следующем примере используется опция с именем overtype. Если эта опция включена, вставка символов приведет к тому, что текст после точки вставки будет перезаписан.

Важные примеры показывают, как вставить текст
(Если тип выделения не является точкой вставки или блоком текста, то следующий код ничего не делает)
public void InsertTextAtSelection()
Word.Selection sln = ThisApplication.Selection;

// Make sure overtype is turned off.
ThisApplication.Options.Overtype = false;

// Является ли текущий объект выделения точкой вставки
// Если да, вставьте абзац символов, а затем вставьте знак абзаца
if (sln.Type == Word.WdSelectionType.wdSelectionIP )
>

// Является ли объект выбора нормальным
else if (sln.Type == Word.WdSelectionType.wdSelectionNormal )
// Проверьте, включена ли опция ReplaceSelection
// Если включено, уничтожить выделение и изменить объект выделения в соответствии с типом точки вставки
// И найдите заголовок предыдущей области выбора
if ( ThisApplication.Options.ReplaceSelection )
Object direction = Word.WdCollapseDirection.wdCollapseStart; sln.Collapse(ref direction);
>
// Вставить текст и метку абзаца
sln.TypeText("Inserting before a text block. "); sln.TypeParagraph();
> else
// Do nothing.
>
>

  1. The Range Object
    Объект Range также представляет диапазон. По сравнению с использованием выбора, диапазон имеет преимущество
     Для выполнения данной задачи требуется меньше кода
     не нужно изменять выбранную область текущего документа (не нужно менять
    highlighting)
     Has greater capabilities

public void SelectSentence()
Word.Range rng;
if (ThisDocument.Sentences.Count >= 2 )
// Supply a Start and end value for the Range.
Object start = ThisDocument.Sentences[2].Start; Object end = ThisDocument.Sentences[2].End; rng = ThisDocument.Range(ref start, ref end); rng.Select();
>
>

// Move the ending position 7 characters.
unit = Word.WdUnits.wdCharacter; count = 7; rng.MoveEnd(ref unit, ref count);
На следующем рисунке показан процесс перемещения вышеуказанного кода

4.3 Получить первый и последний символы диапазона
MessageBox.Show(String.Format(“Start: , End: ”, rng.Start, rng.End), “Range Start and End”);

// Reset the existing Range. rng.SetRange(ThisDocument.Sentences[2].Start, ThisDocument.Sentences[5].End); rng.Select();

4.5 Отформатированный текст
Чтобы указать формат для диапазона, сначала необходимо указать диапазон, а затем применить формат.
Следующий код демонстрирует следующий процесс:

Выберите первый абзац в документе, а затем установите размер шрифта и выравнивание,

всплывающее диалоговое окно

Вызовите метод Undo три раза, чтобы откатить предыдущую операцию

Применить нормальный стиль отступа, а затем всплывающее диалоговое окно

// Change the formatting. rng.Font.Size = 14; rng.Font.Name = “Arial”; rng.ParagraphFormat.Alignment =
Word.WdParagraphAlignment.wdAlignParagraphCenter; rng.Select();
MessageBox.Show(“Formatted Range”, “FormatRangeAndUndo”);
// Undo the three previous actions.
Object times = 3;
ThisDocument.Undo(ref times); rng.Select();
MessageBox.Show(“Undo 3 actions”, “FormatRangeAndUndo”);
// Apply the Normal Indent style. Object style = “Normal Indent”; rng.set_Style(ref style); rng.Select();
MessageBox.Show(“Normal Indent style applied”,
“FormatRangeAndUndo”);

// Undo a single action. times = 1;
ThisDocument.Undo(ref times); rng.Select();
MessageBox.Show(“Undo 1 action”, “FormatRangeAndUndo”); >

Советы: Свернуть не очень хорошо для перевода. С точки зрения непрофессионала, его функция такова: когда ваш объект Range или объект Selection содержит фрагмент текста, используйте метод Collapse (), чтобы сделать
Диапазон, содержащийся в Range или Selection, становится передней точкой вставки или задней точкой вставки исходного текста

Для работы с файлами Word и Excel я решил выбрать библиотеки Microsoft.Office.Interop.Word и Microsoft.Office.Interop.Excel, предоставляющие программные интерфейсы для взаимодействия с объектами MS Word и Excel.

Преимущества использования этих библиотек:

  • созданы корпорацией Microsoft, следовательно, взаимодействие с объектами программ пакета MS Office реализовано наиболее оптимально,
  • нужный пакет Visual Studio Tool for Office поставляется вместе с Visual Studio (достаточно отметить его при установке VS).

Также следует заметить, что у такого похода есть и недостаток: для того, чтобы написанная программа работала на ПК пользователя необходимо, чтобы на нём были установлены программы MS Office и MS Excel. Поэтому такой подход плохо подходит для серверных решений. Также такая программа не будет являться кроссплатформенной.

Добавление библиотек в проект Visual Studio

Для использования библиотеки нужно:

  • добавить ссылку на неё: в обозревателе решений необходимо кликнуть правой кнопкой мыши по пункту Ссылки (Рис. 1) и найти нужную библиотеку по ключевым словам (после добавления ссылка появится в списке),
  • указать используемое пространство имён в файле программы (в примере ему назначен алиас Word): (Рис. 2):

Пример парсинга файла MS Word

Можно прочитать основные форматы: .doc, .docx, .rtf.

Ниже приведён листинг с примером считывания текста из документа MS Word:

  • в коде приводится пример считывания основного текста документа, текста верхних и нижних колонтитулов, а также текста сносок,
  • в коде производится очистка неуправляемых ресурсов с использованием класса Marshal (подробнее можно почитать по ссылке )

Пример парсинга файла MS Excel

Можно прочитать основные форматы: .xls, .xlsx.

Ниже приведён листинг с примером считывания текста из документа MS Excel (по ячейкам):

  • при обработке текста каждой ячейки приходится заранее знать количество задействованных строк и столбцов на текущем листе документа,
  • такой перебор не совсем оптимален (временная сложность алгоритма O(n 2 )): при желании его можно ускорить (например, разбив обработку на несколько потоков): в данной статье приводится лишь пример получения текста из каждой ячейки,
  • при таком переборе ячеек необходимо на каждой итерации освобождать неуправляемые ресурсы, чтобы избежать утечек памяти (аналогично предыдущему примеру, используется класс Marshal).

С помощью указанных библиотек можно не только читать текст из документов, но и создавать новые файлы форматов MS Word и Excel.

Рубрики

Свежие записи

Свежие комментарии

Архивы

1. Подключить нужные библиотеки
2. Открыть шаблон Word
3. Найти в нем нужное место
4. Вставить в него строку с информацией

1. Проект в студии у нас уже должен быть. В разделе Ссылки/References кликаем правой кнопкой, идем в "Добавить ссылку" и ищем Microsoft.Office.Interop.Word. В параметрах добавленной библиотеки ставим true в Копировать локально/Copy local, так как библиотеку надо копировать вместе с исполняемыми файлами проекта.

В код добавляем соответствующие using

2. Теперь вам предстоит провести много времени с замечательным интерфейсом Word, который представляет сам текстовый редактор и его потроха в виде разнообразных обьектов. Сейчас важны два - Application и Document. Переменные для них по ряду не очевидных причин лучше объявлять через интерфейсы.

Так же почти все функции Word требуют объектных параметров, даже если внутри них сидят простые строки и логические значения, так что лучше заранее сделать несколько оберток

Чтобы запустить Word и открыть в нем шаблон с диска (путь известен), потребуется примерно такой код

Принципиально важны два момента

1. Мы создаем неуправляемый ресурс, который не соберет сборщик мусора - отдельный процесс в памяти с приложением Word, если мы его не закроем и не выведем на экран, он так и останется там висеть до выключения компьютера. Более того такие ворды могут накапливаться незаметно для пользователя, программист-то еще прибьет их вручную. Заботиться о высвобождения неуправляемого ресурса должен программист.

2. По умолчанию Word запускается невидимым, на экран его выводим мы.

Для начала рассмотрим самый простой и примитивный вариант - поиск и замена строки в документе Word. Некоторые программисты так и работают - ставят в шаблон текстовую метку вроде @@nowDate и заменяют ее на нужное значение.

Пришло время познакомится с фундаментом работы с Word - великим и ужасным объектом Range. Его суть сложно описать словами -это некоторый произвольный кусок документа, диапазон (range), который может включать в себя все что угодно - от пары символов, до таблиц, закладок и прочих интересных вещей. Не стоит путать его с Selection - куском документа, выделенным мышкой, который само собой можно конвертировать в Range. Соотвественно нам надо получить Range для всего документа, найти нужную строку внутри него, получить Range для этой строки и уже внутри этого последнего диапазона заменить текст на требуемый. И не стоит забывать, что документ может иметь сложную структуру с колонтитулами и прочей ересью, возможный универсальный метод для замены всех вхождений данной строки:

На самом деле это не самый лучший метод для вставки информации в документ, так как могут возникнуть сложности с уникальными именами для текстовых меток (если текст одной входит в начало другой, данный метод найдет ее и заменит), их совпадением с произвольным текстом и так далее.

Даже если нам надо найти (и например отформатировать) именно строку с текстом внутри документа, лучше всего выдать наружу найденный Range и уже с ним производить разные злодеяния. Получим примерно такой метод:

Простейшее решение проблемы уникальности текста (нужно нам найти Range слова Word, но внутри всего документа оно встречается десятки раз) - искать строку внутри строки, сначала найти уникальную строку, потом не уникальную внутри нее, неэстетично, но дешево, надежно и практично.

Если строку надо просто заменить, то сойдет простейшее

Но так как Range является универсальный контейнером для любого куска документа Word, то его возможности неизмеримо шире, часть их будет рассмотрена в дальнейших заметках.

Если нам надо просто встать в начало документа (и что-то вставить уже туда):

0856_WordToOpenXmlTutor_ru/image1.jpg

Введение

Office Open XML, также известный как OpenXML или OOXML, представляет собой формат на основе XML для офисных документов, включая текстовые документы, электронные таблицы, презентации, а также диаграммы, фигуры и другой графический материал. В июне 2014 года Microsoft выпустила исходный код Open XML SDK на GitHub для работы с таким форматом.

У этой библиотеки есть серьёзные преимущества:

Без минусов тоже не обошлось:

Эти минусы определённо дополняют друг друга. Собственно, это и стало причиной создания этого материала.

Боль разработчиков Office

Основы

Прежде чем приступить к разбору примеров, стоит понять, с чем вообще работают эти две библиотеки и в чём состоит разница их подходов.

Word документ — это набор запакованных xml-документов. Все элементы структурированы под тегами.

Например, параграф внутри документа будет выглядеть примерно вот так:

Сборка Interop.Word немного абстрагируется от этой структуры и часто работает с некоторым участком – Range – документа. А Open XML SDK идёт по пути отражения внутренней структуры документа в самом коде. Параграфы <w:p>, участки текста <w:t> и всё остальное становятся объектами в самом коде. Если вы не создадите тело документа, параграф и других обязательных "родителей", то и добавлять текст будет некуда.

0856_WordToOpenXmlTutor_ru/image2.jpg

На скриншоте как раз изображена внутренняя структура основного файла для документа Word – document.xml. Этот файл содержит само наполнение документа.

Скриншот сделан в очень нужной для работы с Open XML утилите Open XML SDK 2.5 Productivity Tool. К моменту написания статьи эта утилита была удалена с сайта Microsoft, а в репозитории Open-XML-SDK добавлена ссылка на некий DocxToSource, который должен стать заменой устаревшего Productivity Tool. Однако эта замена всё ещё является прототипом, поэтому пока лучше постараться найти старый добрый Productivity Tool. Старая утилита позволяет просмотреть строение документа, познакомиться с автогенерированным кодом.

0856_WordToOpenXmlTutor_ru/image3.jpg

Также она позволяет сравнить два разных документа (и код для их создания, и их внутреннее строение).

0856_WordToOpenXmlTutor_ru/image4.jpg

Примеры

Для Interop.Word во всей статье примем такой псевдоним для удобства чтения:

Также для упрощения будем называть Open XML SDK просто Open XML.

Создание документа

Interop.Word:

Тут всё достаточно просто, но всё равно есть свои подводные камни. При работе с Interop мы взаимодействуем не просто с некоторым объектом в памяти, а с COM-объектом. Поэтому возникает необходимость завершать все процессы после окончания работы программы. Эта проблема не раз поднималась на Stack Overflow (1, 2), и ей предложено множество разных решений.

Есть решение с участием Marshal Class, являющимся частью InteropServices.

Однако в таком случае можно упустить какие-нибудь процессы.

Есть более надёжный вариант с обращением к GC:

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

Если не завершить процессы, то при активном дебаге можно устроить себе такую ситуацию:

0856_WordToOpenXmlTutor_ru/image5.jpg

Но даже если в коде присутствует закрытие процессов после окончания работы, при прерывании программы вручную или её падении процесс останется запущенным. Такого недостатка нет при создании и работе с документом через Open XML.

Open XML:

Обратите внимание на добавление SectionProperties, они понадобятся нам позже.

Добавление параграфа

Interop.Word

Текст также можно сделать жирным или курсивным через параметр Font:

Изменить размер шрифта можно через:

Выравнивание текста выполняется через ParagraphFormat.Alignment:

Open XML:

В случае с Open XML жирным или курсивным текст можно сделать через:

Изменение размера шрифта в этом случае немного неинтуитивно, но согласуется с общей логикой работы с Open XML:

Важно перед этим не забыть добавить к параграфу свойства:

Вставка заголовка

Предположим, что нам нужно вписать в документ заголовок. В случае Interop.Word нужно всего лишь небольшое дополнение к вставке текста, чтобы получить заголовок:

Interop.Word:

В этом случае сначала задаём Range для записи нового текста и присваиваем ему стиль Heading 1.

Open XML:

Тут, казалось бы, всё очень похоже. Аналогично добавляем параграф и в случае с Open XML организуем нужную иерархию объектов.

Однако на самом деле в случае с Open XML коварным оказывается добавление стиля. Interop.Word работает с реальным полноценным документом, как если бы вы запустили Word и нажали создать. А вот Open XML работает только с тем, что было создано. И если вы добавляете текст документу, созданному через Open XML, а не через Interop.Word, то в нём будут отсутствовать, например, стили. Соответственно, никакого стиля Heading1 в таком документе не будет. Его нужно сначала добавить.

Удобнее всего добавлять нужный стиль при создании документа. Есть два варианта: перенести стили из готового Word-документа или добавить эти стили вручную.

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

Для второго варианта нам поможет Productivity Tool для Open XML, упоминавшийся ранее. Чтобы получить код, нужный для добавления желаемого стиля, создаём чистый документ Word, используем в нём нужный стиль и "скармливаем" этот документ утилите. Далее через использование кнопки Reflect Code на /word/styles.xml в структуре документа мы получим реализацию метода GeneratePartContent. В нём мы ищем реализацию нужного стиля и всё, что с ним связано, включая StyleParagraphProperties, StyleRunProperties и т.д.

Для стиля Heading 1 нужный нам автосгенерированный код будет выглядеть примерно так:

Чтобы добавить перенесённый стиль к генерируемому документу, нужно создать набор стилей Styles и добавить стиль к набору. Далее к документу нужно добавить StyleDefinitionsPart и присвоить группу стилей. Выглядеть это будет вот так:

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

Смена ориентации страницы

Для нашего отчёта нам нужна была именно ландшафтная ориентация страницы.

Interop.Word:

У документа получаем нужный Range (страниц или всего документа) и задаём ландшафтную ориентацию.

Open XML:

C Open XML в этом случае всё не настолько абстрактно, как хотелось бы. Если вы инициализируете в PageSize только поле Orient, то ничего не изменится. Width и Height тоже нужно менять.

Гиперссылки

Interop.Word:

Тут всё просто: как обычно, получаем нужный Range и добавляем гиперссылку. У метода Add много параметров, и можно сконструировать более сложную ссылку.

Open XML:

Из существенных отличий тут то, что url нужно сначала обернуть в Uri и создать связь url с гиперссылкой через AddHyperlinkRelationship. Потом при создании самой гиперссылки, нужно присвоить полю Id новой гиперссылки Id созданной ранее связи.

Картинки

Interop.Word:

Тут всё достаточно просто, а с Open XML всё оказалось крайне сложно.

Open XML:

Для добавления картинки необходимо соблюсти сложную иерархию объектов с определёнными параметрами. Хорошо, что есть документация на этот счёт. Поэтому пропустим код, требуемый для добавления картинки в этой статье. Разберём ещё один момент, который почему-то не упоминается в документации. Можете заметить, что в том коде нигде не передаётся размер картинки. Фиксируется её размер тут:

Если использовать этот код, то вместо нормальной картинки, будет вставлено малюсенькое изображение. Его реальный размер никак не изменится, но при отображении оно будет отмасштабировано до таких размеров:

Дело в том, что масштаб отображения картинки здесь завязан на такую вещь, как EMU (English Metric Units).

Для того чтобы передавать методу добавления картинки привычные размеры в пикселях, потребуется следующее преобразование:

Тут мы получаем количество EMU на пиксель, приняв значение PPI за 96, и умножаем полученное значение на нужное количество пикселей для ширины и высоты. В итоге у наc есть нужная нам ширина и высота в EMU. Их мы и передаём как Cx и Cy для Extent и Extents:

Таблицы

Interop.Word:

Генерация таблицы через Interop.Word достаточно прямолинейна. Разберём пример, как можно было бы вставить таблицу из квадратной матрицы строк.

Параметры метода AddDefaultTableBehavior и AutoFitBehavior — как видно из их названия, отвечают за поведение таблицы при необходимости изменения размера под содержимое ячеек. Им присваиваются значения перечислений WdDefaultTableBehavior и WdAutoFitBehavior соответственно. Сам метод Add создаёт в документе таблицу с нужными нам параметрами.

Стиль к таблице можно применить следующим образом:

Также для красивого выделения первого столбика, если он является заголовочным, можно присвоить true полю oTable.ApplyStyleFirstColumn.

Расстояние между параграфами текста контролируется через oTable.Range.ParagraphFormat.SpaceAfter. Для компактного отображения таблицы можно использовать

Также можно устанавливать тип написания текста к строкам или колонкам:

Используя эти возможности, можно получить вот такую таблицу:

0856_WordToOpenXmlTutor_ru/image7.jpg

Open XML:

При создании таблицы с нуля с Open XML стоит помнить о том, что никаких ячеек или строк к моменту ввода данных не существует. Их нужно сначала создать, соблюдая внутреннюю иерархию.

Поэтому при проходе по матрице мы для каждой строки создаём TableRow, а потом для каждого элемента в строке создаём TableCell, куда добавляем новые Paragraph, Run и Text с соответствующим значением из матрицы. TableCellProperties лучше также добавить сразу, чем потом при дальнейшей работе с таблицей наткнуться на System.NullReferenceException при попытке добавить свойство ячейке.

Если мы не зададим в TableProperties ни стиля, ни Borders, то таблица будет выглядеть вот так

Границы таблицы формируются через TableBorders.

Перечисление BorderValues здесь задаёт стиль границ.

TableBorders нужно добавить к TableProperties через

Границы таблицы можно не задавать, если ей будет присвоен какой-нибудь стиль. Главное не забыть, что стиль сначала нужно добавить к документу.

Задаётся стиль достаточно просто:

Его так же, как и границы, нужно добавить к TableProperties:

Для того чтобы таблица заняла всю ширину страницы можно использовать TableWidth заданную следующим образом:

Значение 5000 тут взято "не из воздуха". Тип единицы ширины здесь мы задаём TableWidthUnitValues.Pct – единицы ширины в одну пятидесятую процента страницы или 0,02%. В итоге пять тысяч Pct это 100% ширины страницы.

Этот параметр добавляется к TableProperties аналогичным образом:

Важный момент: TableProperties должны быть добавлены к таблице до самих данных для того, чтобы они работали корректно. Их можно добавить и после других объектов, но тогда уже стоит использовать

Раскраска таблиц

Для формирования нашего отчёта нам нужно было раскрасить ячейки в некоторых таблицах документа.

Interop.Word:

где oTable – это созданная нами ранее таблица, i и j — это индексы нужной ячейки. Присваиваемое значение – перечисление WdColor.

Open XML:

где tc – это TableCell, с которой идёт работа. Полю Fill присваивается строка с Hex-значением цвета.

Разрыв страницы

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

Interop.Word:

Open XML:

Тип разрыва меняется через перечисление BreakValues.

Footer/Header

Также нам нужны были футеры/хедеры в документе.

Interop.Word:

Через headerRange.Font можно поменять параметры текста, например размер, шрифт, цвет и т.д. А headerRange.ParagraphFormat.Alignment, как следует из названия, задаёт выравнивание текста. Это поле принимает значения WdParagraphAlignment.

Open XML:

Тут сложность состоит в том, что футер/хэдер сам по себе хранится в отдельном .xml файлике. Поэтому нам нужно связать хэдер/футер с содержанием документа через SectionProperties.

Если нужно, чтобы текст перезаписывался на новый при вызове метода добавления хедера, то вместо

Для футера нужно будет передать mainDocumentPart.FooterParts.

Заключение

Описанные методы работы с Open XML SDK можно собрать в библиотеку классов для внутреннего использования в компании, что мы и сделали. Создание Word документов стало даже удобнее, чем было с Word Interop API.

Здесь может возникнуть закономерный вопрос, есть ли готовые библиотеки на основе Open XML SDK для упрощённой работы с документами? Ответ – однозначно да. Но, к сожалению, поддержка таких библиотек быстро прекращается. Истории создания таких проектов все одинаковые: программисты начинают работать с Word, осознают неудобство существующей инфраструктуры, дорабатывают её — и некоторые библиотеки публикуются на GitHub. Даже если удастся найти относительно свежую версию подобной библиотеки, то, скорее всего, она была реализована под задачи конкретного проекта, и в вашем проекте всё равно будет неудобной в использовании. Плюс появится риск остаться с неподдерживаемой библиотекой.

Читайте также: