TX Text Control .NET for WPF

Fields, Hyperlinks, and Bookmarks

Topic

If your application needs to find a value in a document again, replace it later or link it to a website or another page, it marks that text as a field. The WPF TextControl supports general text fields, MS Word fields such as merge fields, hyperlinks, bookmarks and links to bookmarks, and it tells your code through events when the user clicks or changes one.

The examples use a window with a TextControl named textControl1, as in Create Your First WPF Application. The handlers belong in MainWindow.xaml.cs, which needs using TXTextControl; and using System.Windows;.

Kinds of Fields

All fields are based on TextField: a marked piece of text with a name, an ID and events. The WPF TextControl has one collection per kind of field:

ClassRepresentsCollection
TextFieldA general field, for example for a value from a databaseWPF.TextControl.TextFields
ApplicationFieldA field of MS Word, such as MERGEFIELD or DATEWPF.TextControl.ApplicationFields
HypertextLinkA link to a URL or a file outside the documentWPF.TextControl.HypertextLinks
DocumentTargetA bookmark, a named position in the documentWPF.TextControl.DocumentTargets
DocumentLinkA link to a bookmark of the same documentWPF.TextControl.DocumentLinks

Each collection contains the fields of the text part with the input focus, which is the main text, a header or footer, or a text frame. Form fields are covered on Form Fields and Conditional Instructions, and page numbers, which are PageNumberField objects in headers and footers, on Headers and Footers.

Insert and Fill Text Fields

private void InsertField_Click(object sender, RoutedEventArgs e)
{
    TextField customerField = new TextField("Customer name")
    {
        Name = "CustomerName",
        ID = 100,
        HighlightMode = HighlightMode.Activated,
        // Let users type in front of and behind the field
        DoubledInputPosition = true
    };

    if (textControl1.TextFields.CanAdd)
    {
        textControl1.TextFields.Add(customerField);
    }
}

private void FillFields_Click(object sender, RoutedEventArgs e)
{
    foreach (TextField field in textControl1.TextFields)
    {
        if (field.Name == "CustomerName")
        {
            field.Text = "Paul Paulsen";
        }
    }
}

Connect the handlers to two buttons, for example <Button Content="Insert Field" Click="InsertField_Click" /> next to the TextControl in MainWindow.xaml.

  • The TextField constructor takes the visible text, which Text reads and replaces later.
  • Name and ID are values of your own that identify the field. They are saved with the document and also copied when the user copies the field through the clipboard. Name takes any string, and its length isn't limited, so a field can carry a large amount of data of your own.
  • HighlightMode gives the field a gray background: Activated while the input position is in it, Always, or Never, the default.
  • DoubledInputPosition creates two input positions at each end of the field, one inside and one outside, which users reach with the arrow keys.
  • CanAdd is false at positions where no field can be inserted, such as inside another field. TextFieldCollection.Add inserts the field at the input position.

Set Editable to false to keep users from changing the text of a field, and Deleteable to false to keep them from deleting it. FieldCursor sets the mouse cursor over fields.

Find and Remove Fields

private void RemoveField_Click(object sender, RoutedEventArgs e)
{
    TextField field = textControl1.TextFields.GetItem(100);

    if (field != null)
    {
        // true: keep the text of the field in the document
        textControl1.TextFields.Remove(field, true);
    }
}

private void ListAllFields_Click(object sender, RoutedEventArgs e)
{
    StringBuilder list = new StringBuilder();

    foreach (TextField field in textControl1.GetTextFields(TextFieldType.All))
    {
        list.AppendLine(field.GetType().Name + " " + field.Name + ": " + field.Text);
    }

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

StringBuilder needs using System.Text;.

  • GetItem returns the field at the input position, or the one with an ID. Remove removes it; with true, its text stays in the document.
  • WPF.TextControl.GetTextFields collects fields of several kinds at once, selected with TextFieldType: TextField, ApplicationField, HypertextLink, DocumentLink, FormFields, All and others.

Text Field Events

The WPF TextControl raises the following events. Their handlers receive a TextFieldEventArgs, and its TextField property is the field:

EventOccurs when
TextFieldCreated, TextFieldDeletedA field is inserted or deleted, also through the clipboard, undo or redo
TextFieldChangedThe text of a field has changed, but not its formatting
TextFieldClicked, TextFieldDoubleClickedA field is clicked or double-clicked
TextFieldEntered, TextFieldLeftThe input position moves into or out of a field

Connect a handler as an attribute of the control, TextFieldClicked="textControl1_TextFieldClicked". This one shows the name of the clicked field in the title bar of the window:

private void textControl1_TextFieldClicked(object sender, TextFieldEventArgs e)
{
    Title = "Clicked: " + e.TextField.Name;
}

A field pasted from the clipboard keeps the name and ID of the original. Rename it in a TextFieldCreated handler if your code expects unique names.

In a TextFieldDeleted handler, the field is no longer part of the document: of the TextField in the event arguments, only ID and Name hold valid values. To find out which field was deleted, compare these two.

TextFieldDoubleClicked is raised for every field whose DoubleClickEvent property is true, the default. While the event is raised, a double-click on the field doesn't select a word as it does in other text. Set DoubleClickEvent to false for a field to get the normal word selection back and no event.

Load MS Word Fields

ApplicationField objects represent the fields of MS Word documents. They are created when a document is loaded with LoadSettings.ApplicationFieldFormat set to MSWord:

private void LoadWordFields_Click(object sender, RoutedEventArgs e)
{
    LoadSettings loadSettings = new LoadSettings()
    {
        // Load MS Word fields as ApplicationField objects
        ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
        ApplicationFieldTypeNames = new string[] { "MERGEFIELD", "DATE" }
    };

    textControl1.Load("template.docx", StreamType.WordprocessingML, loadSettings);

    StringBuilder list = new StringBuilder();

    foreach (ApplicationField field in textControl1.ApplicationFields)
    {
        // For a MERGEFIELD, the first parameter is the field name
        string[] parameters = field.Parameters ?? new string[0];
        list.AppendLine(field.TypeName + " " + string.Join(" ", parameters));
    }

    MessageBox.Show(this, list.ToString());
}
  • ApplicationFieldTypeNames restricts the import to the listed field types. When it isn't set, all MS Word fields are loaded.
  • TypeName is the type of the field, and Parameters are the field name and the switches: for MERGEFIELD Address \* Upper, the first element is Address.

Change the Text and the Parameters

The visible text of an application field is its Text, as for every field. Parameters is a .NET array, and .NET arrays have a fixed size: to add or remove a switch, build a new array and assign it to Parameters. The following handler shows a value in the MERGEFIELD named Address and removes the \v switch from all fields that have it:

private void ChangeWordFields_Click(object sender, RoutedEventArgs e)
{
    foreach (ApplicationField field in textControl1.ApplicationFields)
    {
        string[] parameters = field.Parameters;

        if (parameters == null)
        {
            continue;
        }

        if (field.TypeName == "MERGEFIELD" && parameters[0] == "Address")
        {
            field.Text = "Bakerstreet, London";
        }

        // Copy all parameters except the \v switch into a new array
        int index = Array.IndexOf(parameters, "\\v");

        if (index >= 0)
        {
            string[] newParameters = new string[parameters.Length - 1];
            Array.Copy(parameters, newParameters, index);
            Array.Copy(parameters, index + 1, newParameters, index, parameters.Length - index - 1);
            field.Parameters = newParameters;
        }
    }
}

Array needs using System;. A field without parameters has null as Parameters, which the handler skips. Filling merge fields with data is the job of the MailMerge class and of the Reporting tab: see Merge Fields.

Word Form Fields and Content Controls

With ApplicationFieldFormat.MSWord, the legacy form fields and the content controls of a Word document are imported as application fields too, with their settings as Office Open XML markup in Parameters. Content Controls lists their type names, shows which ApplicationFieldFormat turns them into which fields and reads and changes them with field adapters.

To edit Word form fields with the form fields of TX Text Control instead, load the document with ApplicationFieldFormat.MSWordTXFormFields, or with the default None: see Form Fields and Conditional Instructions. Loading Documents lists all values of ApplicationFieldFormat, including HighEdit for the fields of the Heiler HighEdit component.

Next Steps