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

Работа с таблицами в документах Word — одна из наиболее часто используемых операций. В Open XML работа с таблицами, как и с обычным текстом, осуществляется с использованием нескольких классов, позволяющих создавать объект таблицы, указывать оформление таблицы и добавлять в ячейки таблицы данные. В этой части мы рассмотрим то, как создать простую таблицу в Word с использованием Open XML и заполнить её данными.

Работа с таблицами. Класс Table

Класс Table в Open XML представляет собой объект таблицы. По сути, этот класс выступает обычным контейнером для элементов таблицы, в вся функциональность по работе с таблицами расположена в других классах, таких как TableProperties, TableCellProperties и так далее. Рассмотрим пример создания таблицы в документе Word, а, затем, перейдем к изучению классов и их свойств для работы с таблицами.

static void Main(string[] args)
{
    using WordprocessingDocument doc = WordprocessingDocument.Create("hello.docx", WordprocessingDocumentType.Document);
    MainDocumentPart mainPart = doc.AddMainDocumentPart();
    mainPart.Document = new Document();
    Body body = mainPart.Document.AppendChild(new Body());
    
    Table table = new Table();
    TableProperties tableProperties = new TableProperties()
    {
        TableBorders = new TableBorders()
        {
            TopBorder = new TopBorder() { Val=BorderValues.Single, Size=4},
            LeftBorder = new LeftBorder() { Val = BorderValues.Single, Size = 4 },
            RightBorder = new RightBorder() { Val = BorderValues.Single, Size = 4 },
            BottomBorder = new BottomBorder() { Val = BorderValues.Single, Size = 4 },
            InsideHorizontalBorder = new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
            InsideVerticalBorder = new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
        },
        TableWidth = new TableWidth() { Type=TableWidthUnitValues.Auto, Width = "0" }
    };
    table.AddChild(tableProperties);

    for (int i = 0; i < 10; i++) 
    {
        TableRow row = new TableRow();
        for (int j = 0; j < 10; j++) 
        {
            TableCell cell = new TableCell();
            cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
            TableCellProperties properties = new TableCellProperties()
            {
                TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Pct, Width="1" }
            };
            cell.Append(properties);
            row.Append(cell);
        }
        table.Append(row);
    } 
    body.AddChild(table);
 }

Работа с таблицей начинается с создания объекта типа Table:

Table table = new Table();

Затем, мы создаем объект типа TableProperties в котором устанавливаем настройки границ таблицы и её ширины:

TableProperties tableProperties = new TableProperties()
{
    TableBorders = new TableBorders()
    {
        TopBorder = new TopBorder() { Val=BorderValues.Single, Size=4},
        LeftBorder = new LeftBorder() { Val = BorderValues.Single, Size = 4 },
        RightBorder = new RightBorder() { Val = BorderValues.Single, Size = 4 },
        BottomBorder = new BottomBorder() { Val = BorderValues.Single, Size = 4 },
        InsideHorizontalBorder = new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
        InsideVerticalBorder = new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
    },
    TableWidth = new TableWidth() { Type=TableWidthUnitValues.Pct, Width = "5000" }
};

Стоит в очередной раз обратить внимание на то, что в Open XML мы работаем с тем, что есть, поэтому мы описываем каждую границу таблицы — верхнюю, левую, правую, нижнюю, а также внутренние горизонтальные и вертикальные границы. Далее, здесь же, в настройках таблицы мы устанавливаем её ширину:

TableWidth = new TableWidth() { Type=TableWidthUnitValues.Pct, Width = "5000" }

Величина 5000 указана здесь не просто так и не «с потолка». Мы уже сталкивались с единицами измерения dxa в Open XML. Здесь же мы сталкиваемся с ещё одной единицей измерения, которая может использоваться в документах Word — Pct (одна пятидесятая процента). Соответственно, 5000 pct = 5000/50 = 100%. Таким образом, в коде выше мы устанавливаем ширину таблицы равной 100%. Также, свойство Type у объекта TableWidth может принимать следующие значения:

  • Auto — ширина определяется автоматически
  • Dxa — единицы измерения dxa (одна двадцатая дюйма)
  • Pct — единицы измерения pct (одна двадцатая процента)
  • Nil — ширина не указывается

После создания объекта TableProperties мы сразу же добавляем его в объект типа Table.

table.AddChild(tableProperties);

Далее, мы заполняем таблицу данными — запускаем цикл по строкам и ячейкам таблицы. Вначале, во внешнем цикле, мы добавляем к таблице новую строку (TableRow)

for (int i = 0; i < 10; i++) 
{
    TableRow row = new TableRow();
    //тут работаем со строкой таблицы
    table.Append(row);
}

Как и объект Table, TableRow выступает контейнером для других элементом — ячеек таблицы. Поэтому во внутреннем цикле мы создаем объект ячеек и уже в ячейки записываем данные:

for (int j = 0; j < 10; j++) 
{
    TableCell cell = new TableCell();
    cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
    TableCellProperties properties = new TableCellProperties()
    {
        TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Auto, Width="0" }
    };
    cell.Append(properties);
    row.Append(cell);
}

Ячейки таблицы могут иметь различные свойства, поэтому, для примера, мы устанавливаем для каждой ячейки ширину. Объекты ячеек добавляются в строки. В результате выполнения этого примера мы получим таблицу следующего вида:Работа с таблицами в Open XML и C#Учитывая то, что данные в таблицу добавляются также, как и в сам документ — с использованием объектов Paragraph и Run, то здесь мы получаем все те же возможности по оформлению текста таблицы — мы можем выравнивать текст в каждой ячейке, работать с отступами, цветом текста и заливки и так далее. Теперь рассмотрим более подробно настройки таблицы.

Класс TableProperties — настройка таблицы

Класс TableProperties в Open XML устанавливает настройки объекта таблицы в документе и предоставляет нам следующие свойства:

Свойство Тип Описание
 Shading Shading? Затенение таблицы. С помощью этого свойства можно установить цвет заливки таблицы и выбрать узор заливки. С объектами этого класса мы знакомы по примерам работы с абзацами.
 TableBorders TableBorders? Определяет внешний вид границ таблицы, используя шесть типом: верхняя, нижняя, левая, правая, внутренняя горизонтальная и внутренняя вертикальная границы. Пример использования этого свойства см. выше.
 TableCaption TableCaption? Заголовок таблицы. Значение этого объекта определяется в MS Word как «Замещающий текст», который доступен в меню «Свойства таблицы — Замещающий текст»
 TableCellMarginDefault TableCellMarginDefault? Задает значение полей ячеек по умолчанию
 TableCellSpacing TableCellSpacing? Задает интервал между ячейками таблицы
 TableDescription TableDescription? Описание таблицы. Значение этого объекта определяется в MS Word как «Описание», которое доступно в меню «Свойства таблицы — Замещающий текст»
 TableIndentation TableIndentation? Задает отступ, который должен быть добавлен перед передним краем текущей таблицы в документе
 TableJustification TableJustification? Задает выравнивание таблицы в документе
 TableLayout TableLayout? Задает алгоритм, который будет использоваться для размещения содержимого этой таблицы в документе. Когда таблица отображается в документе, она может отображаться с помощью алгоритма макета фиксированной ширины или автоподбора
 TableLook TableLook? Указывает, какие компоненты стиля таблицы применяются к текущей таблице, если для таблицы установлен стиль
 TableOverlap TableOverlap? Указывает, должна ли текущая таблица разрешать другим таблицам перекрывать ее при отображении в документе.
 TablePositionProperties TablePositionProperties? Определяет фиксированное положение таблицы в документе
 TableStyle TableStyle? Задает стиль таблицы
 TableWidth TableWidth? Задает ширину таблицы. Пример использования этого свойства см. выше.

Рассмотрим примеры использования некоторых из этих свойств.

Как в Open XML задать по умолчанию поля ячеек в таблице?

Для того, чтобы установить по умолчанию поля ячеек в таблице необходимо использовать свойство TableCellMarginDefault. Класс TableCellMarginDefault устанавливает значения левого (StartMargin), правого (EndMargin), верхнего (TopMargin) и нижнего (BottomMargin) полей. Размеры полей устанавливаются также с использованием единиц измерения Pct или Dxa. Например, установим поля ячеек по умолчанию равными 0,25 см. Изменим объект tableProperties в примере выше следующим образом:

TableProperties tableProperties = new TableProperties()
{
    //устанавливаем поля ячеек по умолчанию
    TableCellMarginDefault = new TableCellMarginDefault() 
    {
        BottomMargin = new BottomMargin() { Type=TableWidthUnitValues.Dxa, Width=$"{CmToDxa(0.25)}"},
        TopMargin = new TopMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
        StartMargin = new StartMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
        EndMargin = new EndMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
    },
    TableBorders = new TableBorders()
    {
        TopBorder = new TopBorder() { Val=BorderValues.Single, Size=4},
        LeftBorder = new LeftBorder() { Val = BorderValues.Single, Size = 4 },
        RightBorder = new RightBorder() { Val = BorderValues.Single, Size = 4 },
        BottomBorder = new BottomBorder() { Val = BorderValues.Single, Size = 4 },
        InsideHorizontalBorder = new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
        InsideVerticalBorder = new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
    },
    TableWidth = new TableWidth() { Type=TableWidthUnitValues.Pct, Width = "5000" },
};

Теперь наша таблица примет следующий вид:Работа с таблицами в Open XML и C#

Как в Open XML установить автоподбор ширины таблицы по содержимому?

Для того, чтобы в Open XML установить автоподбор ширины таблицы по содержимому, необходимо использовать свойство  TableLayout. Объект типа TableLayout предоставляет нам свойство Type, которое может принимать следующие значения:

  • TableLayoutValues.Autofit — автоподбор ширины таблицы по содержимому
  • TableLayoutValues.Fixed — фиксированный размер

Так, чтобы наша таблица использовала автоподбор по содержимому, необходим изменить настройки таблицы следующим образом:

TableProperties tableProperties = new TableProperties()
{
    TableCellMarginDefault = new TableCellMarginDefault() 
    {
        BottomMargin = new BottomMargin() { Type=TableWidthUnitValues.Dxa, Width=$"{CmToDxa(0.25)}"},
        TopMargin = new TopMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
        StartMargin = new StartMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
        EndMargin = new EndMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
    },
    //Shading = new Shading() { Color = "auto", Val = ShadingPatternValues.DiagonalCross, Fill="ff0000" },
    TableBorders = new TableBorders()
    {
        TopBorder = new TopBorder() { Val=BorderValues.Single, Size=4},
        LeftBorder = new LeftBorder() { Val = BorderValues.Single, Size = 4 },
        RightBorder = new RightBorder() { Val = BorderValues.Single, Size = 4 },
        BottomBorder = new BottomBorder() { Val = BorderValues.Single, Size = 4 },
        InsideHorizontalBorder = new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
        InsideVerticalBorder = new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
    },
    //автоподбор по содержимому
    TableLayout = new TableLayout() 
    {
        Type = TableLayoutValues.Fixed,
       
    }
   // TableWidth = new TableWidth() { Type=TableWidthUnitValues.Pct, Width = "5000" },
   
};

Класс TableCellProperties — настройка ячеек таблицы

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

Свойство Тип Описание
 GridSpan GridSpan? Указывает количество столбцов сетки в таблице, которые должны быть объединены с текущей ячейкой
 HorizontalMerge HorizontalMerge? Указывает, что эта ячейка является частью горизонтально объединенного набора ячеек в таблице. Свойство Val для этого элемента определяет, как определяется текущая ячейка относительно предыдущей — продолжает ли эта ячейка горизонтальное слияние или запускает новую объединенную группу ячеек
 NoWrap NoWrap? Указывает, как должна быть размещена эта ячейка при отображении таблицы в документе. Свойство используется только , когда для таблицы установлен автоматическим подбор ширины
 Shading Shading? Заливка ячейки
 TableCellBorders TableCellBorders? Набор свойств, описывающих внешний вид границ ячейки
 TableCellFitText TableCellFitText? Указывает, должен ли текст сжиматься, чтобы вписываться в границы ячейки или ячейка должна изменять свою ширину, чтобы уместить весь текст
 TableCellMargin TableCellMargin? Поля ячейки таблицы
 TableCellVerticalAlignment TableCellVerticalAlignment? Определяет вертикальное выравнивание содержимого ячейки
 TableCellWidth TableCellWidth? Ширина ячейки таблицы
 TextDirection TextDirection? Определяет направление текста в ячейке
 VerticalMerge VerticalMerge? Указывает, что эта ячейка является частью вертикально объединенного набора ячеек в таблице.

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

Как в Open XML изменить направление текста в ячейке таблицы?

Для того, чтобы в Open XML изменить направление текста в ячейке таблицы, необходимо использовать свойство TextDirectionв свойстве Val которого необходимо указать одно из значений перечисления TextDirectionValues.

Значение перечисления Описание
BottomToTopLeftToRight Снизу вверх, слева направо.
LefToRightTopToBottom Слева направо, сверху вниз.
LefttoRightTopToBottomRotated Слева направо, сверху вниз зеркально
TopToBottomLeftToRightRotated Сверху вниз, слева направо зеркально
TopToBottomRightToLeft Сверху вниз, справа налево.
TopToBottomRightToLeftRotated Сверху вниз, справа налево зеркально.

Изменим в нашем примере внутренний цикл (в котором добавляются ячейки) следующим образом:

for (int j = 0; j < 10; j++) 
{
    TableCell cell = new TableCell();
    cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
    TableCellProperties properties = new TableCellProperties()
    {
        TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Auto, Width="0" },
        //выравнивание по вертикали - по центру
        TableCellVerticalAlignment = new TableCellVerticalAlignment() { Val=TableVerticalAlignmentValues.Center},
        //направление текста снизу вверх слева направо
        TextDirection = new TextDirection() { Val=TextDirectionValues.BottomToTopLeftToRight},
    };
    cell.Append(properties);//добавляем настройки в ячейку
    row.Append(cell); //добавляем ячейку в строку
}

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

Работа с таблицами в Open XML и C#

Как в Open XML объединять строки и столбцы таблицы?

Для того, чтобы в Open XML объединять строки и столбцы таблицы мы должны использовать свойства HorizontalMerge или VerticalMerge при настройке каждой ячейки таблицы, которые должны попасть в объединенный набор. Например, объединим все ячейки в столбцах, начиная с четвертого, переписав внутренний цикл следующим образом:

for (int j = 0; j < 10; j++) 
{
    TableCell cell = new TableCell();
    cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
    TableCellProperties properties = new TableCellProperties()
    {
        TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Auto, Width="0" },
        //выравнивание по вертикали - по центру
        TableCellVerticalAlignment = new TableCellVerticalAlignment() { Val=TableVerticalAlignmentValues.Center},
        //направление текста снизу вверх слева направо
        TextDirection = new TextDirection() { Val=TextDirectionValues.BottomToTopLeftToRight},
        
    };
    if (j>3)
        properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Continue };
    else
    {
        properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Restart };
    }
        
    cell.Append(properties);//добавляем настройки в ячейку
    row.Append(cell); //добавляем ячейку в строку
}

Теперь запустим приложение и посмотрим на результат:Работа с таблицами в Open XML и C#

Добавление заголовка таблицы в Open XML

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

Чтобы в Open XML определить строку таблицы как заголовок, необходимо в эту строку добавить специальный объект типа TableHeader. Например, сделаем в нашей таблице заголовком первую строку. Для этого перепишем код заполнения таблицы следующим образом:

for (int i = 0; i < 50; i++) 
{
    TableRow row = new TableRow();
    if (i == 0) //строка заголовка
        row.TableRowProperties = new TableRowProperties(new TableHeader() { Val = OnOffOnlyValues.On });
    for (int j = 0; j < 10; j++) 
    {
        TableCell cell = new TableCell();
        if (i == 0) //ячейка заголовка
            cell.AddChild(new Paragraph(new Run(new Text($"Заголовок {i}"))
            {
                RunProperties = new RunProperties() { Bold = new Bold() }
            }));
        else
           {
              cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
           }
            TableCellProperties properties = new TableCellProperties()
            {
                TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Auto, Width = "0" },
                //выравнивание по вертикали - по центру
                TableCellVerticalAlignment = new TableCellVerticalAlignment() { Val = TableVerticalAlignmentValues.Center },
            };
        if (j>3)
            properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Continue };
        else
        {
            properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Restart };
        }
            
        cell.Append(properties);//добавляем настройки в ячейку
        row.Append(cell); //добавляем ячейку в строку
    }
    table.Append(row);
}

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

Работа с таблицами в Open XML и C#

Полный код примера рассмотренного в этой части:

using DocumentFormat.OpenXml;

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace OpenDocumentPocessor
{
    internal class Program
    {
        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());
            Table table = new Table();

            TableProperties tableProperties = new TableProperties()
            {
                TableCellMarginDefault = new TableCellMarginDefault() 
                {
                    BottomMargin = new BottomMargin() { Type=TableWidthUnitValues.Dxa, Width=$"{CmToDxa(0.25)}"},
                    TopMargin = new TopMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
                    StartMargin = new StartMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
                    EndMargin = new EndMargin() { Type = TableWidthUnitValues.Dxa, Width = $"{CmToDxa(0.25)}" },
                },
                TableBorders = new TableBorders()
                {
                    TopBorder = new TopBorder() { Val=BorderValues.Single, Size=4},
                    LeftBorder = new LeftBorder() { Val = BorderValues.Single, Size = 4 },
                    RightBorder = new RightBorder() { Val = BorderValues.Single, Size = 4 },
                    BottomBorder = new BottomBorder() { Val = BorderValues.Single, Size = 4 },
                    InsideHorizontalBorder = new InsideHorizontalBorder() { Val = BorderValues.Single, Size = 4 },
                    InsideVerticalBorder = new InsideVerticalBorder() { Val = BorderValues.Single, Size = 4 }
                },
              
                
                TableWidth = new TableWidth() { Type=TableWidthUnitValues.Pct, Width = "5000" },
               
            };

            table.AddChild(tableProperties);

            for (int i = 0; i < 50; i++) 
            {
                TableRow row = new TableRow();
                if (i == 0) //строка заголовка
                    row.TableRowProperties = new TableRowProperties(new TableHeader() { Val = OnOffOnlyValues.On });
                for (int j = 0; j < 10; j++) 
                {
                    TableCell cell = new TableCell();
                    if (i == 0) //ячейка заголовка
                        cell.AddChild(new Paragraph(new Run(new Text($"Заголовок {i}"))
                        {
                            RunProperties = new RunProperties() { Bold = new Bold() }
                        }));
                    else
                       {
                          cell.AddChild(new Paragraph(new Run(new Text($"{i} - {j}"))));
                       }
                        TableCellProperties properties = new TableCellProperties()
                        {
                            TableCellWidth = new TableCellWidth() { Type = TableWidthUnitValues.Auto, Width = "0" },
                            //выравнивание по вертикали - по центру
                            TableCellVerticalAlignment = new TableCellVerticalAlignment() { Val = TableVerticalAlignmentValues.Center },
                        };
                    if (j>3)
                        properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Continue };
                    else
                    {
                        properties.HorizontalMerge = new HorizontalMerge() { Val = MergedCellValues.Restart };
                    }
                        
                    cell.Append(properties);//добавляем настройки в ячейку
                    row.Append(cell); //добавляем ячейку в строку
                }
                table.Append(row);
            } 

            TableHeader tableHeader = new TableHeader();
            tableHeader.Val = OnOffOnlyValues.On;
            
            body.AddChild(table);

         }

        public static int CmToDxa(double value)
        {
            //переводим сантиметры в дюймы
            var inches = value / 2.54;
            //переводим дюймы в точки при разрешении 72 dpi
            var dpi = inches * 72;
            //переводим точки в dxa
            var dxa = dpi * 20;
            return (int)Math.Ceiling(dxa);
        }
    }
}

Итого

В этой части мы рассмотрели работы с таблицами в документе Word. Научились добавлять и настраивать свойства таблиц, отдельных ячеек и строк в таблице. Для работы с таблицами в Open XML и C# используются классы Table, TableRow и TableCell, каждый из которых может принимать объект соответствующего типа для настройки внешнего вида того или иного элемента таблицы.

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