Содержание
Работа с таблицами в документах 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);
}
Ячейки таблицы могут иметь различные свойства, поэтому, для примера, мы устанавливаем для каждой ячейки ширину. Объекты ячеек добавляются в строки. В результате выполнения этого примера мы получим таблицу следующего вида:
Учитывая то, что данные в таблицу добавляются также, как и в сам документ — с использованием объектов 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 установить автоподбор ширины таблицы по содержимому?
Для того, чтобы в 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 объединять строки и столбцы таблицы?
Для того, чтобы в 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
Если таблица достаточно большая и не умещается на одной странице документа, то удобно сделать одну или несколько строк в таблице заголовком, который будет повторяться на каждой странице документа.
Чтобы в 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 будет выглядеть следующим образом:
Полный код примера рассмотренного в этой части:
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, каждый из которых может принимать объект соответствующего типа для настройки внешнего вида того или иного элемента таблицы.

