Слияние настольных клеток

Иногда определенные строки в таблице требуют заголовка или больших блоков текста, которые занимают всю ширину таблицы. Для правильного оформления таблицы пользователь может объединить несколько ячеек таблицы в одну. Aspose.Words Поддерживает слияние ячеек при работе со всеми форматами ввода, включая импорт HTML-контента.

Как объединить столовые клетки

В Aspose.Words, Слитые клетки представлены следующими свойствами CellFormat класс:

  • HorizontalMerge Описывает, является ли клетка частью горизонтального слияния клеток
  • VerticalMerge который описывает, является ли клетка частью вертикального слияния клеток

Значения этих свойств определяют слияние поведения клеток:

  • Первая клетка в последовательности слитых клеток будет иметь CellMerge.First
  • Последующие слившиеся клетки будут иметь CellMerge.Previous
  • Ячейка, которая не сливается, будет иметь CellMerge.None

Проверьте, слита ли клетка

Чтобы проверить, является ли клетка частью последовательности слитых клеток, мы просто проверяем HorizontalMerge и VerticalMerge свойств.

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

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document(MyDir + "Table with merged cells.docx");
Table table = (Table) doc.GetChild(NodeType.Table, 0, true);
foreach (Row row in table.Rows)
{
foreach (Cell cell in row.Cells)
{
Console.WriteLine(PrintCellMergeType(cell));
}
}

Слияние настольных клеток при использовании DocumentBuilder

Слияние клеток в таблице, созданной с помощью DocumentBuilder, Вы должны установить соответствующий тип слияния для каждой ячейки, где ожидается слияние. CellMerge.First А потом CellMerge.Previous.

Кроме того, вы должны помнить, чтобы очистить настройку слияний для тех клеток, где слияние не требуется - это можно сделать, установив первую несливающуюся клетку. CellMerge.None. Если этого не сделать, все ячейки в таблице будут объединены.

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

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.InsertCell();
builder.CellFormat.HorizontalMerge = CellMerge.First;
builder.Write("Text in merged cells.");
builder.InsertCell();
// This cell is merged to the previous and should be empty.
builder.CellFormat.HorizontalMerge = CellMerge.Previous;
builder.EndRow();
builder.InsertCell();
builder.CellFormat.HorizontalMerge = CellMerge.None;
builder.Write("Text in one cell.");
builder.InsertCell();
builder.Write("Text in another cell.");
builder.EndRow();
builder.EndTable();
doc.Save(ArtifactsDir + "WorkingWithTables.HorizontalMerge.docx");

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

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.InsertCell();
builder.CellFormat.VerticalMerge = CellMerge.First;
builder.Write("Text in merged cells.");
builder.InsertCell();
builder.CellFormat.VerticalMerge = CellMerge.None;
builder.Write("Text in one cell");
builder.EndRow();
builder.InsertCell();
// This cell is vertically merged to the cell above and should be empty.
builder.CellFormat.VerticalMerge = CellMerge.Previous;
builder.InsertCell();
builder.CellFormat.VerticalMerge = CellMerge.None;
builder.Write("Text in another cell");
builder.EndRow();
builder.EndTable();
doc.Save(ArtifactsDir + "WorkingWithTables.VerticalMerge.docx");

Слияние настольных клеток в других случаях

В других ситуациях, когда DocumentBuilder не используется, например, в существующей таблице, слияние ячеек предыдущим способом может быть не таким простым. Вместо этого мы можем обернуть основные операции, связанные с применением свойств слияния к клеткам, в метод, который значительно облегчает задачу. Этот метод аналогичен методу автоматизации слияния, который называется объединением ряда ячеек в таблице.

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

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
internal void MergeCells(Cell startCell, Cell endCell)
{
Table parentTable = startCell.ParentRow.ParentTable;
// Find the row and cell indices for the start and end cell.
Point startCellPos = new Point(startCell.ParentRow.IndexOf(startCell),
parentTable.IndexOf(startCell.ParentRow));
Point endCellPos = new Point(endCell.ParentRow.IndexOf(endCell), parentTable.IndexOf(endCell.ParentRow));
// Create a range of cells to be merged based on these indices.
// Inverse each index if the end cell is before the start cell.
Rectangle mergeRange = new Rectangle(Math.Min(startCellPos.X, endCellPos.X),
Math.Min(startCellPos.Y, endCellPos.Y),
Math.Abs(endCellPos.X - startCellPos.X) + 1, Math.Abs(endCellPos.Y - startCellPos.Y) + 1);
foreach (Row row in parentTable.Rows)
{
foreach (Cell cell in row.Cells)
{
Point currentPos = new Point(row.IndexOf(cell), parentTable.IndexOf(row));
// Check if the current cell is inside our merge range, then merge it.
if (mergeRange.Contains(currentPos))
{
cell.CellFormat.HorizontalMerge = currentPos.X == mergeRange.X ? CellMerge.First : CellMerge.Previous;
cell.CellFormat.VerticalMerge = currentPos.Y == mergeRange.Y ? CellMerge.First : CellMerge.Previous;
}
}
}
}
view raw merge-cells.cs hosted with ❤ by GitHub

Следующий пример кода показывает, как объединить ряд клеток между двумя указанными клетками:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document(MyDir + "Table with merged cells.docx");
Table table = doc.FirstSection.Body.Tables[0];
// We want to merge the range of cells found inbetween these two cells.
Cell cellStartRange = table.Rows[0].Cells[0];
Cell cellEndRange = table.Rows[1].Cells[1];
// Merge all the cells between the two specified cells into one.
MergeCells(cellStartRange, cellEndRange);
doc.Save(ArtifactsDir + "WorkingWithTables.MergeCellRange.docx");

В зависимости от версии .NET Framework Если вы используете этот метод, вы можете улучшить его, превратив его в метод расширения. В этом случае вы можете вызвать этот метод непосредственно на клетке для слияния ряда клеток, таких как: cell1.Merge(cell2).

Вертикальные и горизонтальные слитые ячейки в таблице HTML

Как уже говорилось в предыдущих статьях, таблица Microsoft Word Это набор независимых рядов. Каждая строка имеет набор клеток, которые не зависят от клеток других строк. Таким образом, в Microsoft Word В таблице нет такого объекта, как “колонка”, а “1-я колонка” - это что-то вроде “набора 1-й ячейки каждой строки в таблице”. Это позволяет пользователям иметь таблицу, в которой, например, 1-й ряд состоит из двух ячеек - 2 см и 1 см, а 2-й ряд состоит из двух разных ячеек - 1 см и 2 см в ширину. И Aspose.Words Поддерживает эту концепцию таблиц.

Таблица в HTML имеет существенно разную структуру: каждая строка имеет одинаковое количество ячеек и (это важно для задачи) каждая ячейка имеет ширину соответствующего столбца, одинаковую для всех ячеек в одном столбце. Если так, HorizontalMerge и VerticalMerge вернуть неверное значение, используйте следующий пример кода:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document(MyDir + "Table with merged cells.docx");
SpanVisitor visitor = new SpanVisitor(doc);
doc.Accept(visitor);
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
/// <summary>
/// Helper class that contains collection of rowinfo for each row.
/// </summary>
public class TableInfo
{
public List<RowInfo> Rows { get; } = new List<RowInfo>();
}
/// <summary>
/// Helper class that contains collection of cellinfo for each cell.
/// </summary>
public class RowInfo
{
public List<CellInfo> Cells { get; } = new List<CellInfo>();
}
/// <summary>
/// Helper class that contains info about cell. currently here is only colspan and rowspan.
/// </summary>
public class CellInfo
{
public CellInfo(int colSpan, int rowSpan)
{
ColSpan = colSpan;
RowSpan = rowSpan;
}
public int ColSpan { get; }
public int RowSpan { get; }
}
public class SpanVisitor : DocumentVisitor
{
/// <summary>
/// Creates new SpanVisitor instance.
/// </summary>
/// <param name="doc">
/// Is document which we should parse.
/// </param>
public SpanVisitor(Document doc)
{
mWordTables = doc.GetChildNodes(NodeType.Table, true);
// We will parse HTML to determine the rowspan and colspan of each cell.
MemoryStream htmlStream = new MemoryStream();
Aspose.Words.Saving.HtmlSaveOptions options = new Aspose.Words.Saving.HtmlSaveOptions
{
ImagesFolder = Path.GetTempPath()
};
doc.Save(htmlStream, options);
// Load HTML into the XML document.
XmlDocument xmlDoc = new XmlDocument();
htmlStream.Position = 0;
xmlDoc.Load(htmlStream);
// Get collection of tables in the HTML document.
XmlNodeList tables = xmlDoc.DocumentElement.GetElementsByTagName("table");
foreach (XmlNode table in tables)
{
TableInfo tableInf = new TableInfo();
// Get collection of rows in the table.
XmlNodeList rows = table.SelectNodes("tr");
foreach (XmlNode row in rows)
{
RowInfo rowInf = new RowInfo();
// Get collection of cells.
XmlNodeList cells = row.SelectNodes("td");
foreach (XmlNode cell in cells)
{
// Determine row span and colspan of the current cell.
XmlAttribute colSpanAttr = cell.Attributes["colspan"];
XmlAttribute rowSpanAttr = cell.Attributes["rowspan"];
int colSpan = colSpanAttr == null ? 0 : int.Parse(colSpanAttr.Value);
int rowSpan = rowSpanAttr == null ? 0 : int.Parse(rowSpanAttr.Value);
CellInfo cellInf = new CellInfo(colSpan, rowSpan);
rowInf.Cells.Add(cellInf);
}
tableInf.Rows.Add(rowInf);
}
mTables.Add(tableInf);
}
}
public override VisitorAction VisitCellStart(Cell cell)
{
int tabIdx = mWordTables.IndexOf(cell.ParentRow.ParentTable);
int rowIdx = cell.ParentRow.ParentTable.IndexOf(cell.ParentRow);
int cellIdx = cell.ParentRow.IndexOf(cell);
int colSpan = 0;
int rowSpan = 0;
if (tabIdx < mTables.Count &&
rowIdx < mTables[tabIdx].Rows.Count &&
cellIdx < mTables[tabIdx].Rows[rowIdx].Cells.Count)
{
colSpan = mTables[tabIdx].Rows[rowIdx].Cells[cellIdx].ColSpan;
rowSpan = mTables[tabIdx].Rows[rowIdx].Cells[cellIdx].RowSpan;
}
Console.WriteLine("{0}.{1}.{2} colspan={3}\t rowspan={4}", tabIdx, rowIdx, cellIdx, colSpan, rowSpan);
return VisitorAction.Continue;
}
private readonly List<TableInfo> mTables = new List<TableInfo>();
private readonly NodeCollection mWordTables;
}

Преобразование в горизонтальное Слияние клеток

Иногда невозможно определить, какие ячейки слиты, потому что некоторые новые версии Microsoft Word Флаги слияния больше не используются, когда ячейки сливаются горизонтально. Но для ситуаций, когда клетки сливаются в ячейку горизонтально по ширине с помощью флагов слияния, Aspose.Words обеспечивает ConvertToHorizontallyMergedCells Способ преобразования клеток. Этот метод просто преобразует таблицу и добавляет новые ячейки по мере необходимости.

Следующий пример кода показывает вышеупомянутый метод в работе:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document(MyDir + "Table with merged cells.docx");
Table table = doc.FirstSection.Body.Tables[0];
// Now merged cells have appropriate merge flags.
table.ConvertToHorizontallyMergedCells();