# Subtext Parts

> Use SubTextPart in a WPF TextControl to name text ranges such as contract clauses, attach JSON data, highlight, save and remove them and handle their events.

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

---

Knowing where a contract clause or a template block begins and ends lets your WPF application store it, replace it or check it later. A subtext part is exactly that: a named range of text in the `TextControl` that can carry data of your own, is highlighted on request and raises events when the user works with it.

The examples use a window with a `TextControl` named `textControl1`, as in [Create Your First WPF Application](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/document-editor/first-application/llms-full.txt). Subtext parts are a programming feature: the ribbon has no buttons for them.

### What a Subtext Part Is

The main text, each header and footer and each text frame of a document is a *text part*. Inside a text part, your code can define *subtext parts*: ranges of characters that have

- a **name** and an **ID**, both optional;
- **data**, a string you choose, such as JSON;
- a **highlight mode** and a **highlight color**.

Users edit the text of a subtext part like any other text, and the subtext part grows as they type in it. When its last character is deleted, the subtext part disappears. Subtext parts may be nested, but not overlap: a nested one must be shorter than the outer one, which has to exist first. Two subtext parts may follow each other directly, and the position between them belongs to the second.

TX Text Control uses subtext parts for its own features, too. In mail merge templates, a subtext part whose name begins with `txmb_` is a merge block; see [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/blocks/llms-full.txt). To let users edit only some parts of a protected document, use editable regions instead, as described in [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/protection/llms-full.txt).

Subtext parts exist since version 23.0; their data was added in version 26.0.

### Mark the Selected Text

Add buttons for the handlers of this page to *MainWindow.xaml*, and connect the event of the last section as an attribute of the `TextControl`:

```xml
<DockPanel>
    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
        <Button Content="Mark Selection" Click="MarkSelection_Click" />
        <Button Content="List" Click="List_Click" />
        <Button Content="Save Clause" Click="SaveClause_Click" />
        <Button Content="Remove" Click="Remove_Click" />
    </StackPanel>
    <WPF:TextControl x:Name="textControl1"
                    SubTextPartEntered="textControl1_SubTextPartEntered" />
</DockPanel>
```

The first handler in *MainWindow.xaml.cs* marks the selection as a subtext part named "clause":

```csharp
using System.IO;
using System.Text;
using System.Windows;
using TXTextControl;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void MarkSelection_Click(object sender, RoutedEventArgs e)
    {
        // Without a start and a length, the current selection is marked
        SubTextPart clause = new SubTextPart("clause", 1)
        {
            HighlightMode = HighlightMode.Always,
            // A System.Drawing.Color, not a System.Windows.Media.Color
            HighlightColor = System.Drawing.Color.FromArgb(60, System.Drawing.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(this, "The subtext part wasn't added: " + result);
        }
    }
}
```

Keep the `namespace` of your project around the class. Select a paragraph and click **Mark Selection**: the paragraph is highlighted in transparent red.

![A 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-wpf/subtext-part-highlighted.d54268a5.webp)

- The [SubTextPart constructor](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/constructor/llms-full.txt) with a name and an ID creates a subtext part without a position, so that the current selection defines it. Another overload takes a one-based start and a length, for example `new SubTextPart("intro", 2, 1, 25)` for the first 25 characters.
- [HighlightMode](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/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-wpf/reference/txtextcontrol/subtextpart/highlightcolor-property/llms-full.txt) is a `System.Drawing.Color`, not a WPF color, so the code names its namespace. Its alpha value must be below 255 to keep the text readable; the default is red with an alpha value of 60.
- [Data](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/data-property/llms-full.txt) stores any string with the subtext part.
- [SubTextPartCollection.Add](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpartcollection/add-method/llms-full.txt), reached through [WPF.TextControl.SubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextparts-property/llms-full.txt), returns a [SubTextPartCollection.AddResult](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpartcollection/addresult-enumeration/llms-full.txt). Values other than `Successful` explain the failure, such as `NoSelection`, `Overlapping` or `SelectionTooComplex`. `Combined` means that the new part directly follows one with the same name and ID and was joined with it.

The collection belongs to the text part with the input focus; each header, footer and text frame has its own.

### List and Find Subtext Parts

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

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

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

- [Number](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/number-property/llms-full.txt) counts the subtext parts in the order of the text, starting with 1, and [NestedLevel](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/nestedlevel-property/llms-full.txt) is 1 for a subtext part that isn't nested.
- [OuterSubTextPart](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/outersubtextpart-property/llms-full.txt) and [GetChildren](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/getchildren-method/llms-full.txt) navigate the nesting, and [GetTextFields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/gettextfields-method/llms-full.txt) returns the fields inside a subtext part.
- [Text](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/text-property/llms-full.txt) is its plain text.

To get one subtext part, call [GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpartcollection/getitem-method/llms-full.txt): without a parameter it returns the subtext part at the input position (with nested parts, the one with the highest nesting level), with a string or a number the first one with that name or ID. [ScrollTo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpart/scrollto-method/llms-full.txt) brings it into view.

### Save and Remove a Subtext Part

```csharp
private void SaveClause_Click(object sender, RoutedEventArgs 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 Remove_Click(object sender, RoutedEventArgs 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-wpf/reference/txtextcontrol/subtextpart/save-method/llms-full.txt) saves only the content of the subtext part, formatted, as a byte array or a string. `File` needs the `using System.IO;` directive shown above, which WPF projects don't import by default.
- [SubTextPartCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextpartcollection/remove-method/llms-full.txt) decides with two Boolean values whether the text and the nested subtext parts stay in the document. When the text is removed, the nested parts go with it.

### Handle Subtext Part Events

The WPF `TextControl` raises [SubTextPartCreated](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartcreated-event/llms-full.txt), [SubTextPartDeleted](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartdeleted-event/llms-full.txt), [SubTextPartEntered](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartentered-event/llms-full.txt), [SubTextPartLeft](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartleft-event/llms-full.txt), [SubTextPartClicked](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartclicked-event/llms-full.txt) and [SubTextPartDoubleClicked](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-wpf/textcontrol/subtextpartdoubleclicked-event/llms-full.txt). Each handler receives a [SubTextPartEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/subtextparteventargs/llms-full.txt) with the subtext part. The handler connected in the XAML above shows the data of the clause the cursor enters:

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

### Subtext Parts in Files

- Saved documents keep the names and IDs of their subtext parts, so that your code finds them again after loading.
- DOCX, DOC and RTF bookmarks that span several characters become subtext parts when [LoadSettings.LoadSubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/loadsettings/loadsubtextparts-property/llms-full.txt) is `true`; by default, they are loaded as document targets at their first character.
- [SaveSettings.OmittedContent](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/savesettings/omittedcontent-property/llms-full.txt) with `OmittedContent.SubTextParts` leaves the subtext parts out of a saved document and keeps their text and formatting. This setting isn't available for PDF.

[Loading and Saving Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/load-save/llms-full.txt) covers load and save settings. 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/) shows further uses, such as storing user information with a subtext part.

### Next Steps

- [Fields, Hyperlinks, and Bookmarks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/fields/llms-full.txt): fields for single values and links.
- [Document Protection and Editable Regions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/protection/llms-full.txt): editable parts of protected documents.
- [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/blocks/llms-full.txt): the subtext parts of mail merge templates.

---

## Nearby

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