Open XML SDK в C#. Работа со стилями

Стиль — это предопределенный набор свойств таблиц, нумерации, абзацев и (или) символов, которые могут применяться к отдельным частям в документе. В предыдущих частях мы работали со свойствами абзацев и текстовых блоков, но, при этом, не затрагивали такой вопрос как Работа со стилями абзацев, например, мы меняли цвет текста или меняли отступы в абзаце, но даже не пытались изменить стиль, например, установить стиль текста «Заголовок 1». Для работы со стилями отдельных частей документа используется класс Style и в этой части мы познакомимся с ним при работе с текстом в Open XML.

Работа со стилями в документе Word

Если вы ранее работали с COM-объектами Word, например, используя Microsoft.Office.Interop.Word, то наверняка знаете, что при такой работе нам достаточно вызвать всего один метод, указав качестве параметра идентификатор стиля, чтобы он был применен к абзацу. При этом, от нас не требуется работа со созданию этого стиля. В Open XML дело обстоит несколько иначе. Так как при работе с Open XML мы не запускаем процесс Word, а фактически, создаем новый документ с нуля, то и работаем мы только с тем, что есть в документе. Если мы не создали и не добавили в документ стиль, то его невозможно применить так же просто как при работе Microsoft.Office.Interop. Поэтому, работа со стилями в Open XML строится по следующему алгоритму:

  1. Создаем необходимый стиль
  2. Добавляем стиль в документ
  3. Используем стиль в любых частях документа, где он доступен.

Рассмотрим этот алгоритм подробно.

Создание нового стиля в Open XML (класс Style)

Класс Style в Open XML задает определение одного стиля в документе Word. Определение стиля можно разделить на три части:

  • Задание общих свойств стиля
  • Определение типа стиля
  • Определение свойств, относящиеся к типу стиля

Общие свойства стиля относятся к набору свойств, которые можно использовать независимо от его типа стиля, например, к общим свойствам стиля в Open XML относятся имя стиля, дополнительные псевдонимы, идентификатор стиля, признаки того, что стиль скрыт, или заблокирован и т. д.

Что касается свойств, относящихся к типы стиля, то набор этих свойств напрямую зависит от типа стиля. Например, если мы создаем стиль для абзаца, то нам становятся доступными свойства абзаца (ParagraphProperties) и свойства отдельных частей текста (RunProperties).

Open XML поддерживает шесть типов определений стилей по значениям атрибута типа определения стиля:

  • Стили абзацев
  • Стили символов
  • Связанные стили (абзац + символ)
  • Стили таблиц
  • Стили нумерации
  • Свойства абзаца и символа по умолчанию

Теперь рассмотрим свойства класса Style.

Свойство Тип Описание
 Aliases Aliases? Задает набор альтернативных имен (алиасов, псевдонимов) для определения стиля. Эти имена можно использовать в пользовательском интерфейсе приложения по мере необходимости. Альтернативные имена должны храниться в свойстве Val этого элемента и разделяться запятыми. Все присутствующие запятые интерпретируются как символ-разделитель, а не как часть альтернативного имени стиля.
AutoRedefine AutoRedefine? Автоматическое слияние пользовательского форматирования с определением стиля. Пример использования этого свойства представлен ниже.
 BasedOn BasedOn? Задает идентификатор родительского стиля, от которого наследуется текущий стиль
 CustomStyle OnOffValue? Указывает, что этот стиль пользовательский
 Default OnOffValue? Указывает, что этот стиль является стилем по умолчанию
 Locked Locked? Указывает, должно ли приложение запретить использование этого стиля при загрузке и(или) изменении документа
 NextParagraphStyle NextParagraphStyle? Этот элемент задает стиль, который автоматически применяется к новому абзацу, созданному после абзаца с этим стилем.
 PrimaryStyle PrimaryStyle? Указывает, должен ли этот стиль рассматриваться как основной при загрузке этого документа приложением.
 SemiHidden SemiHidden? Указывает, должен ли этот стиль быть скрыт в пользовательском интерфейсе при загрузке документа. При этом, мы можем использовать стиль для работы
 StyleHidden StyleHidden? Указывает, должен ли этот стиль быть полностью скрыт из пользовательского интерфейса
 StyleId StringValue? Задает идентификатор стиля, который используется при создании документа
 StyleName StyleName? Задает имя стиля, которое отображается в пользовательском интерфейсе
 StyleParagraphProperties StyleParagraphProperties? Набор свойств абзаца
 StyleRunProperties StyleRunProperties? Набор свойств текста
 StyleTableCellProperties StyleTableCellProperties? Набор свойств ячейки таблицы
 StyleTableProperties StyleTableProperties? Набор свойств таблицы
 Type EnumValue<StyleValues>? Тип стиля
UIPriority UIPriority?  Задает число, которое можно использовать для сортировки набора стилей в пользовательском интерфейсе при загрузке этого документа приложением
 UnhideWhenUsed UnhideWhenUsed? Указывает, должно ли удаляться свойство SemiHidden, если этот стиль используется содержимым документа

Итак, свойства отдельного стиля рассмотрели. Теперь мы можем создать в нашем приложении новый стиль. Чтобы иметь возможность использовать стиль в документе, его необходимо добавить в часть типа StyleDefinitionsPart, которая, в свою очередь добавляется в основную часть документа.

Продемонстрируем работу со стилями на примере. Создадим консольное приложение C#, установим пакет для работы с Open XML (DocumentFormat.OpenXml) и напишем следующий код:

static void Main(string[] args)
{
    //создаем новый документ Word
    using WordprocessingDocument doc = WordprocessingDocument.Create("hello.docx", WordprocessingDocumentType.Document);
    //задаем главную часть документа
    MainDocumentPart mainPart = doc.AddMainDocumentPart();
    //создаем документ
    mainPart.Document = new Document();
    //создаем тело документа
    Body body = mainPart.Document.AppendChild(new Body());
    //добавляем первый параграф
    Paragraph para = body.AppendChild(new Paragraph(
        new Run(
            //в этой строке будут сохраняться начальные и конечные пробелы
               new Text("Это строка первого абзаца"))
        
        )
     );
    //добавляем второй параграф
    Paragraph paragraph = body.AppendChild(new Paragraph(
        new Run(new Text("Этот строка второго абзаца написана красным цветом"))
        {
            RunProperties = new RunProperties()
            {
                Color = new Color() { Val = "ff0000" }
            }
        }) 
    );
    //создаем новый стиль для параграфа
    Style style = new Style() 
    {
        Type = StyleValues.Paragraph, //указываем тип
        StyleId = "myHeading1",//указываем идентификатор стиля
        StyleName = new StyleName() { Val = "Мой заголовок" }, //задаем имя стиля
        //задаем настройки стиля
        StyleRunProperties = new StyleRunProperties()
        {
            Bold = new Bold(),
            FontSize = new FontSize() {Val = "36" },
        }
    };

    var styles = new Styles();
    styles.Append(style);
    mainPart.AddNewPart<StyleDefinitionsPart>();
    mainPart.StyleDefinitionsPart.Styles = styles;

    //устанавливаем стиль для первого абзаца
    para.ParagraphProperties = new ParagraphProperties()
    {
        ParagraphStyleId = new ParagraphStyleId() { Val= "myHeading1" }
    };

    //устанавливаем стиль для второго абзаца
    paragraph.ParagraphProperties = new ParagraphProperties() 
    {
        ParagraphStyleId = new ParagraphStyleId() { Val = "myHeading1" }
    };
 }

Здесь мы создаем два абзаца текста и стиль с идентификатором myHeading1, после чего применяем стиль к обоим абзацам. Рассмотрим подробно часть когда, относящуюся к работе со стилями. Вначале мы создаем отдельный стиль — объект типа Style:

Style style = new Style() 
{
    Type = StyleValues.Paragraph, //указываем тип
    StyleId = "myHeading1",//указываем идентификатор стиля
    StyleName = new StyleName() { Val = "Мой заголовок" }, //задаем имя стиля
    //задаем настройки стиля
    StyleRunProperties = new StyleRunProperties()
    {
        Bold = new Bold(),
        FontSize = new FontSize() {Val = "36" },
    }
};

Вначале мы задаем тип стили — StyleValues.Paragraph (стиль применяется к абзацу). Далее мы задаем общие свойства стиля — его идентификатор и имя:

StyleId = "myHeading1",//указываем идентификатор стиля
StyleName = new StyleName() { Val = "Мой заголовок" }, //задаем имя стиля

Идентификатор используется внутри документа, имя — в приложении, в котором будет открыт наш документ. Далее мы задаем настройки текста в абзаце — жирность и размер шрифта:

StyleRunProperties = new StyleRunProperties()
{
    Bold = new Bold(),
    FontSize = new FontSize() {Val = "36" },
}

После того, как объект стиля создан, мы должны добавить его в документ. Для этого мы создаем коллекцию стилей, в которую добавляем наш объект, далее создаем новую часть документа для хранения стилей и назначаем созданную коллекцию свойству Styles новой части документа:

var styles = new Styles();
styles.Append(style);
mainPart.AddNewPart<StyleDefinitionsPart>();
mainPart.StyleDefinitionsPart.Styles = styles;

Теперь наш стиль может использоваться в документе. Чтобы применить стиль к абзацу, мы указываем его идентификатор в свойстве ParagraphStyleId настроек абзаца.

para.ParagraphProperties = new ParagraphProperties()
{
    ParagraphStyleId = new ParagraphStyleId() { Val= "myHeading1" }
};
//устанавливаем стиль для второго абзаца
paragraph.ParagraphProperties = new ParagraphProperties() 
{
    ParagraphStyleId = new ParagraphStyleId() { Val = "myHeading1" }
};

Запустим приложение и посмотрим на результат:

Open XML SDK. Работа со стилями абзацев

Обратите внимание на то, что во втором абзаце текст так и остался красного цвета. Как говорилось ранее, прямое форматирование применяется в Open XML в последнюю очередь. То есть, вначале был применен стиль и текст второго абзаца получил жирность и свой размер, а затем — был применен красный цвет текста.

Теперь вернемся к свойствам Style и посмотрим на работу свойства AutoRedefine . Включение этого свойства приводит к тому, что мы можем автоматически менять стиль всех абзацев. Добавим это свойство к нашему стилю:

Style style = new Style() 
{
    Type = StyleValues.Paragraph, //указываем тип
    StyleId = "myHeading1",//указываем идентификатор стиля
    StyleName = new StyleName() { Val = "Мой заголовок" }, //задаем имя стиля
      
    AutoRedefine = new AutoRedefine() { Val=OnOffOnlyValues.On},

    //задаем настройки стиля
    StyleRunProperties = new StyleRunProperties()
    {
        Bold = new Bold(),
        FontSize = new FontSize() {Val = "36" },
    }
};

Теперь снова запустите приложение, чтобы создать документ, а затем откройте полученный файл Word и измените любое свойство текста в первом абзаце. Как только меняется настройка текста в одном из абзацев — эта настройка сразу же применяется к стилю и все абзацы с этим стилем меняют свой внешний вид:

Open XML SDK. Работа со стилями абзацевПоходим образом мы можем настраивать и другие типы стилей в Open XML. Однако, остается ещё один момент работы с текстом в Open XML, который стоит рассмотреть, а именно: как изменить шрифт текста?

Как в Open XML изменить шрифт?

Далеко не всегда и всем подходит использование шрифта по умолчанию для темы того же MS Word. Меняются версии Office, меняются темы оформления, а с ними и шрифты по умолчанию. Так, долгое время основным шрифтом в Word был Calibri, сейчас Aptos, что будет завтра — знаеют только разработчики Microsoft. Нам же может потребоваться использовать другой шрифт в документе, например, Arial. Сделать это можно, используя свойство RunFonts для настроек текста в стиле.

Класс RunFonts предоставляет нам следующие свойства (в таблице перечислены основные свойства):

Свойство Тип Описание
 Ascii StringValue? Шрифт для символов, относящихся к типу ASCII.
 AsciiTheme ThemeFontValues>? Шрифт темы для символов, относящихся к типу ASCII.
 HighAnsi StringValue? Шрифт для документов с символами, не являющимися ASCII.
 HighAnsiTheme ThemeFontValues>? Шрифт темы для документов с символами, не являющимися ASCII.

 

В тексте могут использоваться различные символы, например, часть строки может быть на английском, часть на русском, а часть — вообще на китайском. И мы можем задать свои шрифты для каждой группы символов. Например, изменим наш стиль следующим образом:

Style style = new Style() 
{
    Type = StyleValues.Paragraph, //указываем тип
    StyleId = "myHeading1",//указываем идентификатор стиля
    StyleName = new StyleName() { Val = "Мой заголовок" }, //задаем имя стиля
      
    AutoRedefine = new AutoRedefine() { Val=OnOffOnlyValues.On},

    //задаем настройки стиля
    StyleRunProperties = new StyleRunProperties()
    {
        Bold = new Bold(),
        FontSize = new FontSize() {Val = "36" },
        
        RunFonts = new RunFonts() { HighAnsi="Arial", Ascii="Times New Roman"}
    }
};

Здесь мы определили два шрифта — для ASCII- символов и не ASCII. Теперь изменим первый абзац текста, добавив в него строку на английском языке:

Paragraph para = body.AppendChild(new Paragraph(
    new Run(
        //в этой строке будут сохраняться начальные и конечные пробелы
           new Text("Это строка первого абзаца содержит строку Hello World"))
    
    )
 );

Запустим приложение, чтобы убедиться, что, в соответствии с нашим стилем, все английские символы написаны шрифтом Times New Roman, а русские — используют Arial.Open XML SDK. Работа со стилями абзацев

Итого

В этой части мы познакомились с тем, как работать со стилями оформления документа в Open XML, на примере создания стиля абзаца текста. Стили в Open XML добавляются в часть StyleDefinitionsPart как коллекция объектов типа Style. Каждый стиль имеет свое имя, тип, идентификатор, а также настройки, относящиеся к конкретному объекту в документе (абзацу, ячейке таблице и т.д.)

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии