# Tables and Calculations

> Fill Windows Forms tables from data in code with TableCellFormat borders, header rows and column widths, nest tables and read or remove a document's tables.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Document Processing > Tables and Calculations
- **3862 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/tables/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/tables/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/tables/llms-full.txt

---

Invoice line items, price lists and cash flow statements are tables, and the totals under them are calculations. In a Windows Forms application, your code fills a table from data, formats its cells, rows and columns, nests tables and reads the tables of a loaded document. Each step is one button handler for the `TextControl` of a form.

[Create a Document Programmatically](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/document-processing/create/llms-full.txt) inserts a first table with a header row. Inserting tables with the ribbon, working with the table at the input position and calculating with formulas are described in [Tables and Table Formulas](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/tables/llms-full.txt). For a row per record of a data source in a template, use a merge block, as [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt) shows, instead of a loop. *Form1.cs* needs these `using` directives:

```csharp
using System;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using TXTextControl;
```

### How Tables Are Organized

[Tables](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/tables-property/llms-full.txt) returns the tables of the text part with the input focus. A [Table](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/table/llms-full.txt) has the collections `Rows`, `Columns` and `Cells`, numbered from 1, and a table your code adds gets an ID by which [GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablebasecollection/getitem-method/llms-full.txt) returns it later. [How Tables Are Organized](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/tables/#how-tables-are-organized) explains these rules and the units.

### Fill a Table From Data

The following handler writes the line items of an invoice into a new table, with a gray header row that repeats on each page:

```csharp
private void invoiceTableButton_Click(object sender, EventArgs e)
{
    var lineItems = new[]
    {
        new { Description = "TX Text Control .NET for Windows Forms License", Quantity = 1, Price = 1999.00 },
        new { Description = "Priority Support - 12 Months", Quantity = 1, Price = 299.00 }
    };

    textControl1.ResetContents();
    textControl1.Selection.Text = "Invoice INV-2025-001\r\n\r\n";

    // A header row and one row for each item, with the ID 10
    textControl1.Tables.Add(lineItems.Length + 1, 3, 10);
    Table table = textControl1.Tables.GetItem(10);

    // One format for all cells: borders of 1 pt and space left and right of the text
    TableCellFormat cellFormat = new TableCellFormat()
    {
        LeftBorderWidth = 20,
        TopBorderWidth = 20,
        RightBorderWidth = 20,
        BottomBorderWidth = 20,
        LeftTextDistance = 100,
        RightTextDistance = 100
    };

    foreach (TableCell cell in table.Cells)
    {
        cell.CellFormat = cellFormat;
    }

    // Column headings in row 1, repeated on every page
    string[] headings = { "Description", "Quantity", "Price" };

    for (int column = 1; column <= headings.Length; column++)
    {
        table.Cells.GetItem(1, column).Text = headings[column - 1];
    }

    TableRow headerRow = table.Rows.GetItem(1);
    headerRow.IsHeader = true;
    headerRow.CellFormat = new TableCellFormat() { BackColor = Color.LightGray };

    // One row for each item, starting in row 2
    for (int i = 0; i < lineItems.Length; i++)
    {
        int row = i + 2;
        table.Cells.GetItem(row, 1).Text = lineItems[i].Description;
        table.Cells.GetItem(row, 2).Text = lineItems[i].Quantity.ToString(CultureInfo.InvariantCulture);
        table.Cells.GetItem(row, 3).Text = lineItems[i].Price.ToString("0.00", CultureInfo.InvariantCulture);
    }

    // The first column is 3.5 inches wide
    table.Columns.GetItem(1).Width = (int)(3.5 * 1440);
}
```

The code works as follows:

- The size of the table comes from the data: one row per item plus the header row, and 3 columns.
- A [TableCellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecellformat/llms-full.txt) is assigned to every cell through [TableCell.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecell/cellformat-property/llms-full.txt). [TableRow.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablerow/cellformat-property/llms-full.txt) and [TableColumn.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecolumn/cellformat-property/llms-full.txt) format a whole row or column.
- [TableCellCollection.GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecellcollection/getitem-method/llms-full.txt) returns the cell in a row and a column, and [TableCell.Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecell/text-property/llms-full.txt) sets its text.
- [TableRow.IsHeader](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablerow/isheader-property/llms-full.txt) makes the first row part of the table header, which is repeated at the top of each page when the table continues on the next page.
- [TableColumn.Width](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecolumn/width-property/llms-full.txt) sets the width of a column in twips.

### Format Cells, Rows and Columns

The properties of a `TableCellFormat`:

| Property | Sets |
|---|---|
| `BackColor` | The background color |
| `LeftBorderWidth`, `TopBorderWidth`, `RightBorderWidth`, `BottomBorderWidth` | The width of each border in twips |
| `LeftBorderColor`, `TopBorderColor`, `RightBorderColor`, `BottomBorderColor` | The color of each border |
| `LeftTextDistance`, `TopTextDistance`, `RightTextDistance`, `BottomTextDistance` | The distance between the border and the text in twips |
| [VerticalAlignment](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecellformat/verticalalignment-property/llms-full.txt) | `Top`, `Center` or `Bottom` |
| [TextType](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecellformat/texttype-property/llms-full.txt), [NumberFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecellformat/numberformat-property/llms-full.txt) | Whether the text of the cell is a number, and how numbers are displayed |

[TableRow.MinimumHeight](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablerow/minimumheight-property/llms-full.txt) is the height a row has at least; it grows when its text needs more room. With [TableRow.AllowPageBreak](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablerow/allowpagebreak-property/llms-full.txt) set to `false`, a row isn't split across two pages. To format the text of a cell, select the cell with [TableCell.Select](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecell/select-method/llms-full.txt) and set the character and paragraph attributes of the selection:

```csharp
Table table = textControl1.Tables.GetItem(10);

// Bold text in the first cell
table.Cells.GetItem(1, 1).Select();
textControl1.Selection.Bold = true;
```

### Work With the Table at the Input Position

An editor often has buttons that act on the table the user is working in: `Tables.GetItem()` without a parameter returns it, and `Rows.Add`, `Columns.Add` and `MergeCells` work at the input position or on the selected cells. [Work With the Table at the Input Position](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/tables/#work-with-the-table-at-the-input-position) shows these methods and how to move the input position into a cell.

### Calculate With Formulas

A cell can calculate its text from other cells of the same table, like a spreadsheet, with a formula in [TableCell.Formula](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecell/formula-property/llms-full.txt) such as `SUM(C2:C4)`. [Calculate With Formulas](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/tables/#calculate-with-formulas) adds a total row to a table like the one of the first example, and the sections below it describe the formula syntax and the number formats. A cell of the type `TextType.Number` reads its text with the period as decimal separator, whatever the language of the system, which is why the first example writes the prices with `CultureInfo.InvariantCulture`.

[Formula Functions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/formula-functions/llms-full.txt) lists the 85 functions with their arguments, defaults and limits, and [TableCollection.SupportedFormulaFunctions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecollection/supportedformulafunctions-property/llms-full.txt) returns their names at runtime. Excel formulas in tables are part of the Enterprise and Professional editions; see [Editions and Feature Availability](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/overview/editions/llms-full.txt).

### Nest Tables

To put a table into a cell of another table, place the input position in the cell without selecting its text and call `Tables.Add`:

```csharp
private void nestButton_Click(object sender, EventArgs e)
{
    Table outerTable = textControl1.Tables.GetItem(10);

    // Put the input position into cell (1, 1) without selecting text
    outerTable.Cells.GetItem(1, 1).Select();
    textControl1.Selection.Length = 0;

    textControl1.Tables.Add(2, 2, 11);
    Table nestedTable = outerTable.NestedTables.GetItem(11);

    MessageBox.Show($"Nesting level {nestedTable.NestedLevel}, outer table {nestedTable.OuterTable.ID}");
}
```

[Table.NestedTables](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/table/nestedtables-property/llms-full.txt) contains the tables inside a table. [NestedLevel](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/table/nestedlevel-property/llms-full.txt) is 1 for a table that isn't nested, and [OuterTable](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/table/outertable-property/llms-full.txt) returns the table around a nested one.

### Read and Remove Tables

The tables of a loaded document are in the same collections. The following handler lists the tables of the main text with the text of each cell:

```csharp
private void readTablesButton_Click(object sender, EventArgs e)
{
    StringBuilder report = new StringBuilder();
    MainText mainText = textControl1.TextParts.GetMainText();

    foreach (Table table in mainText.Tables)
    {
        report.AppendLine($"Table {table.ID}: {table.Rows.Count} rows, {table.Columns.Count} columns");

        foreach (TableCell cell in table.Cells)
        {
            report.AppendLine($"  ({cell.Row}, {cell.Column}): {cell.Text}");
        }
    }

    MessageBox.Show(report.ToString());
}
```

[TableBaseCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablebasecollection/remove-method/llms-full.txt) with an ID removes that table, for example `textControl1.Tables.Remove(10)`. [TableCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablecollection/remove-method/llms-full.txt) without a parameter removes the table at the input position, and [Clear](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablebasecollection/clear-method/llms-full.txt) removes all tables of the collection.

### Next Steps

- [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt): repeat table rows for each record of a data source.
- [Tables and Table Formulas](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/tables/llms-full.txt): tables and formulas from the user's side.
- [Text, Paragraphs, and Stylesheets](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/text-paragraphs/llms-full.txt): format the text in table cells.
- [Sections, Pages, Headers, and Footers](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/sections-headers/llms-full.txt): give a wide table a page in landscape orientation.

---

## Nearby

- **Previous:** [Text, Paragraphs, and Stylesheets](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/text-paragraphs/llms-full.txt)
- **Next:** [Images, Text Frames, and Shapes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/images-shapes/llms-full.txt)
