# Subtext Parts

> Mark text ranges as SubTextPart objects in a Windows Forms TextControl: highlight them, store data, nest, list, save and remove them and react to their events.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Document Editor > Subtext Parts
- **3107 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/subtext-parts/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/subtext-parts/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/subtext-parts/llms-full.txt

---

The clauses of a contract, the text blocks of a template or a section that must be stored in a database are pieces of a document that your code has to find again. Subtext parts mark such pieces in a `TextControl`: you name them, attach data to them, highlight them, save their content and react when the user moves into them.

The examples extend the application of [Create Your First Windows Forms Application](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/document-editor/first-application/llms-full.txt), with a `TextControl` named `textControl1` on `Form1`. *Form1.cs* needs `using TXTextControl;`. Subtext parts have no ribbon buttons; they are created in code.

### What a Subtext Part Is

A document consists of *text parts*: the main text, the headers and footers, and the text frames. A *subtext part* is a range of characters inside one of them, defined by your code. Each subtext part has:

- a **name** and an **ID**, both optional, to identify it;
- **data**, a string of your own, for example JSON;
- a **highlight mode** and a **highlight color**, to show the user where it is.

The text of a subtext part is ordinary text: users edit it, and the subtext part grows as they type in it. The following rules apply:

- A subtext part covers at least one character. When its last character is deleted, the subtext part is deleted too.
- Subtext parts can be nested, but they can't overlap. A nested subtext part must be shorter than the outer one, and the outer one must be added first.
- Two subtext parts can follow each other directly; the position between them belongs to the second one.

TX Text Control uses subtext parts itself. The merge blocks of mail merge templates are subtext parts whose names begin with `txmb_`, followed by the block name; see [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt). To make parts of a protected document editable, use editable regions, described in [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/protection/llms-full.txt).

Subtext parts were introduced in version 23.0, and their data in version 26.0.

### Mark the Selected Text

The following handler turns the selected text into a subtext part named "clause", highlights it and stores data with it:

```csharp
private void markSelectionButton_Click(object sender, EventArgs e)
{
    // Without a start and a length, the current selection is marked
    SubTextPart clause = new SubTextPart("clause", 1)
    {
        HighlightMode = HighlightMode.Always,
        HighlightColor = Color.FromArgb(60, Color.Red),
        // Data of your own, stored with the document
        Data = "{\"clauseId\":\"C-100\",\"approved\":false}"
    };

    SubTextPartCollection.AddResult result = textControl1.SubTextParts.Add(clause);

    if (result != SubTextPartCollection.AddResult.Successful)
    {
        MessageBox.Show("The subtext part wasn't added: " + result);
    }
}
```

Select a paragraph and click the button: the text gets a transparent red background.

![A TextControl document in which one paragraph is marked as a subtext part and highlighted in transparent red.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/subtext-part-highlighted.d54268a5.webp)

The code works as follows:

- The [SubTextPart constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/constructor/llms-full.txt) with a name and an ID creates a subtext part with a length of zero, which marks the current selection when it is added. The second overload takes a one-based start position and a length: `new SubTextPart("intro", 2, 1, 25)` marks the first 25 characters. A `null` or empty name and an ID of 0 mean none.
- [HighlightMode](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/highlightmode-property/llms-full.txt) is `Always`, `Never`, or `Activated`, which highlights the subtext part only while it contains the input position and the control has the focus. [HighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/highlightcolor-property/llms-full.txt) needs an alpha value below 255, so that the text stays visible; the default is red with an alpha value of 60.
- [Data](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/data-property/llms-full.txt) holds any string. An empty string means no data.
- [SubTextPartCollection.Add](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/add-method/llms-full.txt), called through [TextControl.SubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextparts-property/llms-full.txt), returns a value of [SubTextPartCollection.AddResult](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/addresult-enumeration/llms-full.txt). Besides `Successful`, it reports why nothing was added: `NoSelection`, `Overlapping`, `SelectionTooComplex`, `PositionInvalid`, `AlreadyExists` or `Error`. `Combined` means that the new subtext part directly follows one with the same name and ID and has been merged into it.

`TextControl.SubTextParts` returns the subtext parts of the text part with the input focus. Headers, footers and text frames have their own collections.

### List and Find Subtext Parts

```csharp
private void listButton_Click(object sender, EventArgs e)
{
    StringBuilder list = new StringBuilder();

    foreach (SubTextPart subTextPart in textControl1.SubTextParts)
    {
        list.AppendLine(subTextPart.Number + " " + subTextPart.Name +
            " (level " + subTextPart.NestedLevel + "): " + subTextPart.Text);
    }

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

`StringBuilder` needs `using System.Text;`.

- [Number](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/number-property/llms-full.txt) is the position of the subtext part in the text flow, starting with 1. When an outer and a nested subtext part start at the same position, the outer one has the lower number.
- [NestedLevel](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/nestedlevel-property/llms-full.txt) is 1 for a top-level subtext part. [OuterSubTextPart](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/outersubtextpart-property/llms-full.txt) returns the subtext part that contains this one, and [GetChildren](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/getchildren-method/llms-full.txt) all subtext parts nested in it.
- [Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/text-property/llms-full.txt) is the plain text. [GetTextFields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/gettextfields-method/llms-full.txt) returns the fields inside the subtext part, such as the merge fields of a clause.

[GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/getitem-method/llms-full.txt) finds a single subtext part: without a parameter the one at the input position, which is the one with the highest nesting level when several are nested there, or the first one with a name or an ID. [ScrollTo](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/scrollto-method/llms-full.txt) moves the input position to its beginning and scrolls it into view.

### Save and Remove a Subtext Part

A subtext part can be saved on its own, with its formatting, for example to store a clause in a database or to insert it into another document:

```csharp
private void saveClauseButton_Click(object sender, EventArgs e)
{
    SubTextPart clause = textControl1.SubTextParts.GetItem("clause");

    if (clause != null)
    {
        // Only the text of the subtext part, with its formatting
        clause.Save(out byte[] data, BinaryStreamType.InternalUnicodeFormat);
        File.WriteAllBytes("clause.tx", data);
    }
}

private void removeButton_Click(object sender, EventArgs e)
{
    // The subtext part at the input position, or null
    SubTextPart subTextPart = textControl1.SubTextParts.GetItem();

    if (subTextPart != null)
    {
        // true: keep the text, true: keep nested subtext parts
        textControl1.SubTextParts.Remove(subTextPart, true, true);
    }
}
```

- [SubTextPart.Save](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/save-method/llms-full.txt) writes the content to a byte array or a string in any format of `BinaryStreamType` or `StringStreamType`, such as the TX Text Control format, RTF or HTML.
- [SubTextPartCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/remove-method/llms-full.txt) takes two Boolean values: whether the text stays in the document, and whether nested subtext parts stay. The second one is ignored when the text is deleted.

### React to Subtext Part Events

`TextControl` raises [SubTextPartCreated](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartcreated-event/llms-full.txt) and [SubTextPartDeleted](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartdeleted-event/llms-full.txt), [SubTextPartEntered](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartentered-event/llms-full.txt) and [SubTextPartLeft](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartleft-event/llms-full.txt) when the input position moves into or out of a subtext part, and [SubTextPartClicked](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartclicked-event/llms-full.txt) and [SubTextPartDoubleClicked](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/subtextpartdoubleclicked-event/llms-full.txt). The handlers receive a [SubTextPartEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextparteventargs/llms-full.txt). The following handler shows the name and data of the clause the user enters:

```csharp
public Form1()
{
    InitializeComponent();
    textControl1.SubTextPartEntered += textControl1_SubTextPartEntered;
}

private void textControl1_SubTextPartEntered(object sender, SubTextPartEventArgs e)
{
    Text = e.SubTextPart.Name + ": " + e.SubTextPart.Data;
}
```

### Load and Save Documents With Subtext Parts

- Subtext parts keep their names and IDs when the document is saved and loaded again. Only the TX Text Control format keeps their `Data`; other formats keep the ranges.
- Bookmarks of DOCX, DOC and RTF documents that span several characters are loaded as subtext parts when [LoadSettings.LoadSubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/loadsettings/loadsubtextparts-property/llms-full.txt) is `true`. By default, they become document targets at their first character.
- [SaveSettings.OmittedContent](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/savesettings/omittedcontent-property/llms-full.txt) with `OmittedContent.SubTextParts` saves a document without its subtext parts, but with their text and formatting. It can't be used for PDF.

[Loading and Saving Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/load-save/llms-full.txt) explains `LoadSettings` and `SaveSettings`. The blog article [The Power of SubTextParts: Typical Use Cases](https://www.textcontrol.com/blog/2024/02/09/the-power-of-subtextparts-typical-use-cases/) stores user data with subtext parts and saves them separately.

### Next Steps

- [Fields, Hyperlinks, and Bookmarks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/fields/llms-full.txt): mark single words or values instead of longer text.
- [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/protection/llms-full.txt): let users edit only parts of a document.
- [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt): repeat parts of a template for each record.

---

## Nearby

- **Previous:** [Fields, Hyperlinks, and Bookmarks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/fields/llms-full.txt)
- **Next:** [Form Fields and Conditional Instructions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/form-fields/llms-full.txt)
