Unisci celle di tabella
A volte alcune righe di una tabella richiedono un’intestazione o grandi blocchi di testo che occupano l’intera larghezza della tabella. Per una corretta progettazione della tabella, l’utente può unire più celle della tabella in una sola. Aspose.Words supporta celle unite quando si lavora con tutti i formati di input, inclusa l’importazione di contenuto HTML.
Come unire le celle della tabella
In Aspose.Words, le celle unite sono rappresentate dalle seguenti proprietà della classe CellFormat:
- HorizontalMerge che descrive se la cella fa parte di un’unione orizzontale di celle
- VerticalMerge che descrive se la cella fa parte di un’unione verticale di celle
I valori di queste proprietà determinano il comportamento di unione delle celle:
- La prima cella in una sequenza di celle unite avrà CellMerge.First
- Tutte le celle successivamente unite avranno CellMerge.Previous
- Una cella non unita avrà CellMerge.None
Controlla se la cella è unita
Per verificare se una cella fa parte di una sequenza di celle unite, controlliamo semplicemente le proprietà HorizontalMerge e VerticalMerge.
L’esempio di codice seguente mostra come stampare il tipo di unione di celle orizzontali e verticali:
// 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)); | |
} | |
} |
Unisci celle di tabella quando usi DocumentBuilder
Per unire le celle in una tabella creata con DocumentBuilder, è necessario impostare il tipo di unione appropriato per ciascuna cella in cui è prevista l’unione: prima CellMerge.First e poi CellMerge.Previous.
Inoltre, devi ricordarti di cancellare l’impostazione di unione per quelle celle in cui non è richiesta l’unione: questo può essere fatto impostando la prima cella non unita su CellMerge.None. Se ciò non viene fatto, tutte le celle della tabella verranno unite.
L’esempio di codice seguente mostra come creare una tabella con due righe in cui le celle della prima riga vengono unite orizzontalmente:
// 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"); |
L’esempio di codice seguente mostra come creare una tabella a due colonne in cui le celle nella prima colonna sono unite verticalmente:
// 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"); |
Unisci le celle della tabella in altri casi
In altre situazioni in cui il DocumentBuilder non viene utilizzato, come in una tabella esistente, unire le celle nel modo precedente potrebbe non essere così semplice. Possiamo invece racchiudere le operazioni di base coinvolte nell’applicazione delle proprietà di unione alle celle in un metodo che rende l’attività molto più semplice. Questo metodo è simile al metodo di automazione Unisci, che viene chiamato per unire un intervallo di celle in una tabella.
Il codice seguente unirà le celle della tabella nell’intervallo specificato, iniziando dalla cella specificata e terminando con la cella finale. In questo caso, l’intervallo può estendersi su più righe o colonne:
// 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; | |
} | |
} | |
} | |
} |
L’esempio di codice seguente mostra come unire un intervallo di celle tra due celle specificate:
// 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"); |
A seconda della versione del .NET Framework che stai utilizzando, potresti voler perfezionare questo metodo trasformandolo in un metodo di estensione. In questo caso, puoi chiamare questo metodo direttamente su una cella per unire un intervallo di celle, come cell1.Merge(cell2)
.
Celle unite verticali e orizzontali nella tabella HTML
Come abbiamo detto negli articoli precedenti, una tabella in Microsoft Word è un insieme di righe indipendenti. Ogni riga ha un insieme di celle indipendenti dalle celle delle altre righe. Pertanto, nella tabella Microsoft Word non esiste un oggetto come una “colonna” e la “prima colonna” è qualcosa come “l’insieme delle prime celle di ogni riga nella tabella”. Ciò consente agli utenti di avere una tabella in cui, ad esempio, la prima riga è composta da due celle – 2 cm e 1 cm, e la seconda riga è composta da due celle diverse – 1 cm e 2 cm di larghezza. E Aspose.Words supporta questo concetto di tabelle.
Una tabella in HTML ha una struttura essenzialmente diversa: ogni riga ha lo stesso numero di celle e (è importante per il compito) ogni cella ha la larghezza della colonna corrispondente, la stessa per tutte le celle di una colonna. Pertanto, se HorizontalMerge e VerticalMerge restituiscono un valore errato, utilizzare il seguente esempio di codice:
// 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; | |
} |
Converti in celle unite orizzontalmente
A volte non è possibile rilevare quali celle vengono unite perché alcune versioni più recenti di Microsoft Word non utilizzano più i flag di unione quando le celle vengono unite orizzontalmente. Ma per le situazioni in cui le celle vengono unite in una cella orizzontalmente in base alla larghezza utilizzando i flag di unione, Aspose.Words fornisce il metodo ConvertToHorizontallyMergedCells
per convertire le celle. Questo metodo trasforma semplicemente la tabella e aggiunge nuove celle secondo necessità.
L’esempio di codice seguente mostra il metodo sopra in funzione:
// 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(); |