Howto: Use Text Fields

Marked Text Fields are markers which are inserted in the text. They can be used to implement a wide range of special functions in a text processor. To name just a few:

  • Mail Merge functions
  • Spreadsheet-like calculation fields
  • Bookmarks
  • Automatic table of contents and index generation
  • Hypertext links and targets

Any group of characters within the text can be a marked text field. The maximum number of fields is 65,535. Text Control maintains the positions and numbers of the fields. It also takes care of loading, saving and clipboard operations.

Additional information about text fields can be found in the Technical Articles part in the chapter Text Fields and Hypertext Links.

The source code for this example is contained in the following directories:

  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\VB.NET\TextFields
  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\CSharp\TextFields

Used TX Text Control controls:

  • TXTextControl.WPF.TextControl
  • TXTextControl.WPF.ButtonBar
  • TXTextControl.WPF.RulerBar
  • TXTextControl.WPF.StatusBar

Relevant API Links

A Simple Example

This first sample program will show you how fields are created and what happens when they are clicked on. The code shown here is contained in the following directories:

  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\VB.NET\TextFields\Fields1
  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\CSharp\TextFields\Fields1

The program consists of a form with just one menu item, Insert Field!, with an exclamation mark to say that clicking on this item will cause an immediate action instead of dropping a menu.

The following code is executed when the menu item is clicked on:

private void MenuItem_Click(object sender, RoutedEventArgs e)
{
    TXTextControl.TextField NewField = new TXTextControl.TextField();

    // Insert a new field and increase field ID
    NewField.Text = "[TextField" + fieldID.ToString() + "]";
    NewField.ID = fieldID;
    NewField.DoubledInputPosition = true;
    fieldID += 1;

    textControl1.TextFields.Add(NewField);
}
Private Sub MenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim NewField As New TXTextControl.TextField()

    ' Insert a new field and increase field ID
    NewField.Text = "[TextField" & fieldID.ToString() & "]"
    NewField.ID = fieldID
    NewField.DoubledInputPosition = True
    fieldID += 1

    textControl1.TextFields.Add(NewField)
End Sub

This inserts a field at the current caret position and assigns a unique number to the fields ID property. If you move the cursor over the field, Text Control changes the mouse pointer to a hand cursor to indicate that there is something to click on.

Image

If you click on the field, the application receives a TextFieldClicked event, to which it responds by popping up a window which displays the field number.

Image

Only two lines of code are required for this:

private void textControl1_TextFieldClicked(object sender, TXTextControl.TextFieldEventArgs e)
{
    MessageBox.Show("Field " + fieldID.ToString() + " has been clicked.");
}
Private Sub textControl1_TextFieldClicked(ByVal sender As Object, ByVal e As TXTextControl.TextFieldEventArgs)
    MessageBox.Show("Field " & fieldID.ToString() & " has been clicked.")
End Sub

Bookmarks

This example shows you how to use text fields to create bookmarks. The first version will reference the bookmarks simply by their field numbers. The source code for this example is contained in the following directories:

  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\VB.NET\TextFields\Fields2
  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\CSharp\TextFields\Fields2

The sample application has a Bookmark menu with two items which are named Insert and Go to.... Clicking Insert creates a text field at the current caret position. If a text selection exists, the selected text is converted into a text field.

private void MenuItem_Click_1(object sender, RoutedEventArgs e)
{
    if (textControl1.Text == "")
    {
        MessageBox.Show("Cannot insert a bookmark if the Text Control is empty.");
        return;
    }
    else if (textControl1.Selection.Length == 0)
    {
        textControl1.Selection.Length = 1;
    }


    // Now turn the selected text into a new field
    TXTextControl.TextField NewField = new TXTextControl.TextField();
    NewField.ID = fieldID;
    NewField.Text = textControl1.Selection.Text;
    textControl1.Selection.Text = "";
    fieldID += 1;
    textControl1.TextFields.Add(NewField);
    textControl1.Focus();
}
Private Sub MenuItem_Click_1(ByVal sender As Object, ByVal e As RoutedEventArgs)
    If textControl1.Text = "" Then
        MessageBox.Show("Cannot insert a bookmark if the Text Control is empty.")
    ElseIf textControl1.Selection.Length = 0 Then
        textControl1.Selection.Length = 1
    Else
        ' Now turn the selected text into a new field
        Dim NewField As New TXTextControl.TextField()
        NewField.ID = fieldID
        NewField.Text = textControl1.Selection.Text
        textControl1.Selection.Text = ""
        fieldID += 1
        textControl1.TextFields.Add(NewField)
    End If
End Sub

After typing in some text and inserting a few bookmarks, select the Go To... menu item. This will launch a dialog box which allows you to enter the number of the bookmark to jump to.

Image

Clicking the OK button executes the following procedure:

private void button2_Click(object sender, RoutedEventArgs e)
{
    if (Convert.ToInt32(textBox1.Text) > tx.TextFields.Count)
    {
        MessageBox.Show("Invalid bookmark number!");
    }
    else
    {
        foreach (TXTextControl.TextField Field in tx.TextFields)
        {
            if (Field.ID == Convert.ToInt32(textBox1.Text))
            {
                tx.Selection.Start = Field.Start - 1;
                tx.Selection.Length = Field.Length;
            }
        }
    }
}
Private Sub button2_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    If Convert.ToInt32(textBox1.Text) > tx.TextFields.Count Then
        MessageBox.Show("Invalid bookmark number!")
    Else
        For Each Field As TXTextControl.TextField In tx.TextFields
            If Field.ID = Convert.ToInt32(textBox1.Text) Then
                tx.Selection.Start = Field.Start - 1
                tx.Selection.Length = Field.Length
            End If
        Next
    End If
End Sub

Adding Strings to Text Fields

In commercial word processors, bookmarks are normally referenced by names, not just by numbers. The names are typed in by the user when he creates a bookmark. The Goto Bookmark dialog box then presents a listbox or combobox in which one of the strings can be selected.

The source code for this example is contained in the following directories:

  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\VB.NET\TextFields\Fields3
  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\CSharp\TextFields\Fields3

The Insert Bookmark... menu item in this version of the program creates a dialog box where the user can enter a label for the bookmark.

Image

When the OK button is clicked, the following code is executed:

private void btnOK_Click(object sender, RoutedEventArgs e)
{
    TXTextControl.TextField Field = new TXTextControl.TextField();

    Field.Name = tbFieldName.Text;
    Field.Text = tx.Selection.Text;
    tx.Selection.Text = "";

    if (!tx.TextFields.Add(Field))
        MessageBox.Show("Could not insert a bookmark. The cursor is probably inside a text field.");

    this.Close();
}
Private Sub btnOK_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim Field As New TXTextControl.TextField()

    Field.Name = tbFieldName.Text
    Field.Text = tx.Selection.Text
    tx.Selection.Text = ""

    If Not tx.TextFields.Add(Field) Then
        MessageBox.Show("Could not insert a bookmark. The cursor is probably inside a text field.")
    End If

    Me.Close()
End Sub

First, a marked text field is created at the current caret position. Second, the name of the bookmark, which is the text that has been typed in by the user, is stored in the TextField.Name property.

The Goto Bookmark dialog box contains a combo box which lists all of the bookmarks which have been created so far.

Image

The combo box is filled with the bookmark titles when its Window is loaded:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    foreach (TXTextControl.TextField Field in tx.TextFields)
    {
        lbFields.Items.Add(Field.Name);
    }
}
Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    For Each Field As TXTextControl.TextField In tx.TextFields
        lbFields.Items.Add(Field.Name)
    Next
End Sub

When the OK button is clicked, the bookmark list is searched for the string which has been selected in the combo box, and the corresponding marked text field is selected.

private void btnOK_Click(object sender, RoutedEventArgs e)
{
    foreach (TXTextControl.TextField Field in tx.TextFields)
    {
        if (Field.Name == lbFields.SelectedItem.ToString())
        {
            tx.Selection.Start = Field.Start - 1;
            tx.Selection.Length = Field.Length;
        }
    }

    this.Close();
}
Private Sub btnOK_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    For Each Field As TXTextControl.TextField In tx.TextFields
        If Field.Name = lbFields.SelectedItem.ToString() Then
            tx.Selection.Start = Field.Start - 1
            tx.Selection.Length = Field.Length
        End If
    Next

    Me.Close()
End Sub

Importing and Exporting Fields from and to MS Word

TX Text Control imports and exports all fields that can be inserted into an MS Word document. As described in the technical article, the ApplicationField class provides a special interface to get and set the data and parameters of these fields.

The following two samples show how to use the two most common used fields of MS Word: MERGEFIELD and FORMTEXTBOX.

The source code for these samples is contained in the following directory:

  • Samples\WPF\VB.NET\ApplicationFields
  • Samples\WPF\CSharp\ApplicationFields

Used TX Text Control controls:

  • TXTextControl.WPF.TextControl
  • TXTextControl.WPF.ButtonBar
  • TXTextControl.WPF.RulerBar
  • TXTextControl.WPF.StatusBar
  • TXTextControl.DocumentServer
  • TXTextControl.DocumentServer.Windows.Forms

Relevant API Links

Implementing a MERGEFIELD Class

The MS Word MergeField is the most commonly used field in MS Word and RTF documents. It enables template designers to add additional information to a text field, such as a specific text that should be displayed before or after the field text or the format of the text.

To handle these fields and it's functionality, this sample uses the DocumentServer.Fields.FieldAdapter implemented in the TXTextControl.DocumentServer. These adapters can be used to modify the TextControl.ApplicationFields directly.

After starting the sample, click on File / Load to load a sample document, which contains several merge fields. Set the input position inside an existing field, for sample [COMPANY].

Image

Open the implemented merge field dialog by choosing Edit... from the MergeField main menu.

Image

Using this dialog, it is possible to manipulate all properties of the MergeField instance. Add some text that should be inserted after the field by checking the checkbox Text to be inserted after. Type some text in the appropriate text box and close the dialog by clicking OK.

Open the customer list view form by clicking Merge fields... from the Merge menu entry. Choose a customer by clicking on a specific row and click Merge to merge all merge fields with the database content.

In this process, the ApplicationFieldCollection is used to loop through all inserted fields to replace the text. The following code shows this loop:

DataRow drCustomer = m_customers.Tables[0].Rows[listBox1.SelectedIndex];

foreach (TXTextControl.ApplicationField curField in _tx.ApplicationFields)
{
    if (curField.TypeName != "MERGEFIELD")
        return;

    MergeField mfCurField = new MergeField(curField);

    if(drCustomer.Table.Columns.Contains(mfCurField.Name))
        mfCurField.Text = drCustomer[mfCurField.Name].ToString();
}
Dim drCustomer As DataRow = m_customers.Tables(0).Rows(listBox1.SelectedIndex)

For Each curField As TXTextControl.ApplicationField In _tx.ApplicationFields
    If curField.TypeName <> "MERGEFIELD" Then
        Return
    End If

    Dim mfCurField As New MergeField(curField)

    If drCustomer.Table.Columns.Contains(mfCurField.Name) Then
        mfCurField.Text = drCustomer(mfCurField.Name).ToString()
    End If
Next

Implementing a FORMTEXT Class

The FormText field is used in MS Word to create fillable documents. In many applications, such documents are automated, so that these fields must be readable to be completed automatically. An ApplicationField object acts like a container for all settings (switches) of these fields.

This sample uses the DocumentServer.Fields.FormText field adapter to handle the ApplicationField. Everytime, an ApplicationField of type FORMTEXT should be edited, a new DocumentServer.Fields.FormText field is created:

FormText curFormText = new FormText(textControl1.ApplicationFields.GetItem());
Dim curFormText As New FormText(TextControl1.ApplicationFields.GetItem())

A reference to the ApplicationField is stored in the FormText instance. Similar to the first sample, this ApplicationField is used to get or set the parameters that are mapped to the properties of the new implemented FormText object.

A dialog box is implemented to change the properties of the specific form text field. The dialog represents the properties of the implemented FormText field:

Image

After clicking OK, the specified values in the dialog box are set in the implemented FormText object which writes the parameters of the referenced ApplicationField automatically.

TX Quote Generator - An Advanced Example

This sample program shows how to use Text Control in office applications. The main task of an office application typically is to create documents from information taken from a set of databases. For instance, a quote is generated from a record in an address database and one or more records in an article database.

The program is built up in two steps, starting very simple with only a single address database, and adding more features later on.

The source code for this example is contained in the subfolders Step1 and Step2 of the following directories:

  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\VB.NET\Quote Generator
  • %USERPROFILE%\My Documents\TX Text Control 29.0.NET for WPF\Samples\WPF\CSharp\Quote Generator

Used TX Text Control controls:

  • TXTextControl.WPF.TextControl
  • TXTextControl.WPF.ButtonBar
  • TXTextControl.WPF.RulerBar
  • TXTextControl.WPF.StatusBar

Relevant API Links

Step 1: Creating a Quote from a Database

When the program is started, it displays an address database in a list view control.

Image

The database is a simple XML file, which is displayed with just a few lines of ADO code:

dsAddress.ReadXml(@"..\..\..\address.xml");
dsArticle.ReadXml(@"..\..\..\article.xml");
lbCustomers.DataContext = dsAddress;
lbArticles.DataContext = dsArticle;

lbCustomers.SelectedIndex = 0;
dsAddress.ReadXml(@"..\..\..\address.xml");
dsArticle.ReadXml(@"..\..\..\article.xml");
lbCustomers.DataContext = dsAddress;
lbArticles.DataContext = dsArticle;

lbCustomers.SelectedIndex = 0;

Selecting the File/New Quote menu item takes the current record from the database and creates a document from it. This is done in the following way:

A form containing a Text Control is opened, and a stylesheet is loaded. A stylesheet is a file that serves as a template for the final document. It contains all text parts which are equal to all documents, for instance a phrase like "In reply to your inquiry and according to our general terms of business we are pleased to..", and placeholders for information that is to be inserted from a database, like Address, Date, and so forth. It also defines the font, font size, company logo, and layout, so that all files will have the same look.

Image

Once the stylesheet has been loaded, the placeholders are updated from the database, so that they now contain the real address, name, customer number, and date.

Image

The stylesheet can be edited with the Advanced menu.

Step 2: Adding Articles with a Table

Before you read everything about how it is programmed, you may want to run it and see what it does, so here is a short user's guide first.

  • Start the program. You will see the main form, displaying some customer address records. Select one by clicking on it.
  • Select the File / New Quote menu item. A quote will be generated using the selected customer's name, address and customer number.
  • Click on the Insert / Article menu item. Select one of the articles displayed in the dialog box that pops up, and click OK. The product data will automatically be entered into the quote.
  • Enter the desired quantity. The total will be recalculated accordingly.
  • Repeat step 3 to enter more articles (clicking into an empty table row first). Delete the remaining empty lines by selecting them with the mouse and clicking Edit / Delete table rows.
  • Finished. Click File / Print to make a printout of the quote.

The first thing we need to do in order to add article descriptions and pricing to our quotes from Step 1 is to add another database. We call it the article database, and display it on the main form beside the address database.

Image

That's it for the main form. On the editor form, we now add a menu item which lets us insert items from the article data into a quote.

A list of articles is best displayed in a table, and Text Control offers all required table functions to let us insert product IDs, descriptions, and prices into the respective cells, as well as to perform calculations. We therefore add a table to the style sheet and adjust its column widths, text distances, and caption text so that later only the plain text needs to be filled in.

This is what the style sheet now looks like:

Image

A new menu item has been added to the Advanced menu, which allows to insert a table. Also, a Format/Table menu item has been created which calls Text Control's table attribute dialog box, so that we can adjust the table grid lines and background shading. The table's column widths and tabs are adjusted in the ruler bar. Note that the 2 rightmost columns have decimal tabs, so that the currency values they will contain will be properly aligned at the decimal sign.

We are now ready to fill in text from the article database into the table. Have a look at the sample program's ArticleTable class, which shows how to use the various table, row, columns and cell collections and objects.

After the user has selected a product in the article database, the program performs these steps:

  • It checks if the current input position is in a row of the article table, where a product can be inserted. If not, it uses the first row below the caption.
  • It inserts the selected product code, product description, and price.
  • Whenever Text Control sends a Changed event while the current input position was inside a table, the total is recalculated accordingly.