# Tables and Calculations

> Create and fill tables in a WPF window, format cells and rows, change the table at the input position and add self-updating SUM formulas with number formats.

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

---

A table in a TX Text Control document can calculate: a total under a column of prices updates itself when a price changes, much like a cell in a spreadsheet. Before that, your code creates the table, fills it from data, formats it and changes its structure. Each task is a `Click` handler for the `TextControl` of a WPF window, including work on the table the user is in.

A first table with a header row is part of [Create a Document Programmatically](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/document-processing/create/llms-full.txt). How users insert and format tables with the ribbon is covered in [Tables and Table Formulas](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/llms-full.txt), and a table row that repeats for each record of a data source is a merge block, described in [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/blocks/llms-full.txt). *MainWindow.xaml.cs* needs these `using` directives:

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

### How Tables Are Organized

A [Table](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/table/llms-full.txt) has rows, columns and cells numbered from 1, your code finds it by its ID or at the input position, and its widths and borders are twips, as [How Tables Are Organized](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/#how-tables-are-organized) in Tables and Table Formulas describes. In processing code, one more rule matters: [Tables](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/tables-property/llms-full.txt) of the `TextControl` returns the [TableCollection](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecollection/llms-full.txt) of the text part with the input focus, which is a header, footer or text frame while the user edits one. [Document Object Model](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/object-model/#the-input-focus-decides-what-a-collection-contains) describes the rule. Table widths and borders don't depend on the `PageUnit` of the control.

### Fill a Table From Data

The following handler creates the line item table of an invoice, with a gray header row that is repeated on each page:

```csharp
private void InvoiceTableButton_Click(object sender, RoutedEventArgs e)
{
    var lineItems = new[]
    {
        new { Description = "TX Text Control .NET for WPF 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);
    TXTextControl.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 (TXTextControl.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];
    }

    TXTextControl.TableRow headerRow = table.Rows.GetItem(1);
    headerRow.IsHeader = true;
    headerRow.CellFormat = new TableCellFormat() { BackColor = System.Drawing.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 table has one row per item plus the header row, and 3 columns. `Tables.Add`, `Cells.GetItem`, `IsHeader` and the column width work as in [Insert a Table From Code](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/#insert-a-table-from-code).
- A single [TableCellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecellformat/llms-full.txt) goes to every cell through [TableCell.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecell/cellformat-property/llms-full.txt). [TableRow.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablerow/cellformat-property/llms-full.txt) and [TableColumn.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecolumn/cellformat-property/llms-full.txt) format a row or a column at once, here the gray header row.
- The numbers are written with `CultureInfo.InvariantCulture`, so their decimal separator is the period that number cells and formulas expect.

### Format Cells, Rows and Columns

A `TableCellFormat` has these properties:

| Property | Sets |
|---|---|
| `BackColor` | The background color, as a `System.Drawing.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-wpf/reference/txtextcontrol/tablecellformat/verticalalignment-property/llms-full.txt) | `Top`, `Center` or `Bottom` |
| [TextType](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecellformat/texttype-property/llms-full.txt), [NumberFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecellformat/numberformat-property/llms-full.txt) | Whether the text of the cell is a number, and how numbers are displayed |

Inside a window, `VerticalAlignment` alone means the layout property of the window. Write the value with its namespace, as in `VerticalAlignment = TXTextControl.VerticalAlignment.Center`.

[TableRow.MinimumHeight](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablerow/minimumheight-property/llms-full.txt) is the smallest height of a row, which grows with its text. [TableRow.AllowPageBreak](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablerow/allowpagebreak-property/llms-full.txt) set to `false` keeps a row on one page. To format the text in a cell, select it with [TableCell.Select](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecell/select-method/llms-full.txt), then use the selection:

```csharp
TXTextControl.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

Commands such as **Insert Row Below** act on the table the user is in: `Tables.GetItem()` without a parameter returns it, `Rows.Add` and `Columns.Add` insert rows and columns next to the input position, and `Table.Select` with `MergeCells` merges cells. [Work With the Table at the Input Position](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/#work-with-the-table-at-the-input-position) in Tables and Table Formulas shows the code, with buttons that are enabled only while the input position is in a table. [TableCell.Row](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecell/row-property/llms-full.txt) and [TableCell.Column](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecell/column-property/llms-full.txt) of `Cells.GetItem()` tell where in the table the input position is.

[InputPosition](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/inputposition-property/llms-full.txt) moves the input position into a cell from code, for example before your code adds a row there. [TableCell.Start](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecell/start-property/llms-full.txt) counts from 1, and the [InputPosition](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/inputposition/constructor/llms-full.txt) constructor expects a text position that counts from 0, as the next example shows.

### Calculate With Formulas

Formulas in table cells follow the syntax of Office Open XML spreadsheet formulas. [Calculate With Formulas](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/#calculate-with-formulas) in Tables and Table Formulas explains how to switch the calculation on, choose the A1 or R1C1 reference style, make cells numbers with a number format, set a formula and catch the `FormulaException` of an invalid one, and it describes constants, operators, functions and cell references with a result for each example. [Number Formats](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/tables/#number-formats) on the same page gives the rules for number formats, and [Formula Functions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/formula-functions/llms-full.txt) describes each of the 85 functions.

The following handler adds a total row to the invoice table of the first example. It moves the input position into the last row before adding a row, so it works whatever the user clicked last:

```csharp
private void TotalButton_Click(object sender, RoutedEventArgs e)
{
    textControl1.FormulaReferenceStyle = FormulaReferenceStyle.A1;
    textControl1.IsFormulaCalculationEnabled = true;

    TXTextControl.Table table = textControl1.Tables.GetItem(10);

    if (table == null)
    {
        return;
    }

    // Put the input position into the last row and add a row below it
    TXTextControl.TableCell lastCell = table.Cells.GetItem(table.Rows.Count, 1);
    textControl1.InputPosition = new InputPosition(lastCell.Start - 1);
    table.Rows.Add(TableAddPosition.After, 1);

    int totalRow = table.Rows.Count;
    table.Cells.GetItem(totalRow, 1).Text = "Total";

    TableCellFormat amountFormat = new TableCellFormat()
    {
        TextType = TextType.Number,
        NumberFormat = "#,##0.00"
    };

    for (int row = 2; row <= totalRow; row++)
    {
        table.Cells.GetItem(row, 3).CellFormat = amountFormat;
    }

    // The sum of the price column, from row 2 to the row above the total
    table.Cells.GetItem(totalRow, 3).Formula = $"SUM(C2:C{totalRow - 1})";
}
```

Formulas can make a whole report calculate itself. In the following cash flow table from Text Control's spreadsheet sample, the green rows are formulas that add up the rows above them:

![A cash flow table with yearly columns in which the green subtotal rows are calculated from the rows above them by table formulas.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/table-formulas-cash-flow.890554ea.webp)

The how-to sample *Howto\\Spreadsheet*, installed with TX Text Control .NET for WPF, builds a formula bar in which the user selects a function from the function list and clicks **Add function**:

![The function list of the Spreadsheet how-to sample, here in its Windows Forms version, opened over the Cash Flow Report with SUM selected among functions from ODD to TYPE.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/formula-function-list.549e8c8f.webp)

The sample then asks for the cell range of the formula:

![The formula box of the Spreadsheet how-to sample, here in its Windows Forms version, with SUM() and a Next Step tip asking for the cell range, for example SUM(A1:A5).](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/formula-cell-range-tip.63ad725f.webp)

Text Control's feature comparison lists Excel formulas for the Enterprise and Professional editions.

### Nest Tables

A table goes into a cell of another table when the input position is in the cell, with no text selected, and `Tables.Add` is called:

```csharp
private void NestButton_Click(object sender, RoutedEventArgs e)
{
    TXTextControl.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);
    TXTextControl.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-wpf/reference/txtextcontrol/table/nestedtables-property/llms-full.txt) holds the tables inside a table. [NestedLevel](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/table/nestedlevel-property/llms-full.txt) is 1 for a table at the top level, and [OuterTable](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/table/outertable-property/llms-full.txt) is the table around a nested one.

### Read and Remove Tables

A loaded document's tables are in the same collections. The following handler lists the tables of the main text and the text of their cells:

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

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

        foreach (TXTextControl.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-wpf/reference/txtextcontrol/tablebasecollection/remove-method/llms-full.txt) removes the table with an ID, as in `textControl1.Tables.Remove(10)`. Without a parameter, [TableCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecollection/remove-method/llms-full.txt) removes the table at the input position, and [Clear](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/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-wpf/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-wpf/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-wpf/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-wpf/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-wpf/document-processing/text-paragraphs/llms-full.txt)
- **Next:** [Images, Text Frames, and Shapes](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/images-shapes/llms-full.txt)
