ผสานเซลล์ตาราง

บางครั้งบางแถวในตารางจำเป็นต้องมีส่วนหัวหรือบล็อกข้อความขนาดใหญ่ที่ใช้ความกว้างเต็มตาราง เพื่อการออกแบบตารางที่เหมาะสม ผู้ใช้สามารถรวมเซลล์ตารางหลายเซลล์ให้เป็นเซลล์เดียวได้ 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 เซลล์ ขนาด 2 ซม. และ 1 ซม. และแถวที่ 2 ประกอบด้วยเซลล์ที่แตกต่างกัน 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();