Fields
Fields mark the parts of a document that code finds and changes later: a customer name, a link to a website, a bookmark, a Word merge field. On the server, you insert these fields, find them in the main text, headers, footers and text frames, change and remove them and turn them into plain text before a document leaves your application.
Merge fields that MailMerge fills with data are covered in Merge Fields, and the content controls of MS Word forms in Content Controls. Every program below replaces the content of Program.cs in a console application.
The Kinds of Fields
A field is a marked piece of text with properties such as a name. Each kind of field has a collection of its own:
| Field | Collection of ServerTextControl | Used for |
|---|---|---|
| TextField | TextFields | Text that your code identifies by its name or ID |
| ApplicationField | ApplicationFields | Fields of MS Word, such as MERGEFIELD, IF and DATE |
| HypertextLink | HypertextLinks | Links to a website or another document |
| DocumentTarget | DocumentTargets | Bookmarks, positions that links point to |
| DocumentLink | DocumentLinks | Links to a bookmark in the same document |
| PageNumberField | HeaderFooter.PageNumberFields | Page numbers in headers and footers, described in Headers and Footers |
| FormField | FormFields | Form fields that users fill out, described in Form Fields |
Keep these points in mind:
- Main text only. The collections of
ServerTextControlcontain the fields of the main text. Headers, footers and text frames have the same collections for their own fields. - Word fields need a load setting. Fields of MS Word documents are imported as application fields only when
LoadSettings.ApplicationFieldFormatis set before loading, as Load a Document shows. - Several kinds at once. GetTextFields returns the fields of the kinds you combine from TextFieldType, such as
TextFieldType.HypertextLink | TextFieldType.DocumentLink.
Insert a Text Field
A text field is inserted at the current input position. The following program writes a label and inserts a field with the customer name behind it:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Selection.Text = "Customer: ";
// A name and an ID let your code find the field again
TextField customerField = new TextField("Acme Corporation")
{
Name = "CustomerName",
ID = 1
};
if (tx.TextFields.CanAdd && tx.TextFields.Add(customerField))
{
Console.WriteLine($"Field inserted at position {customerField.Start}");
}
tx.Save("fields.tx", StreamType.InternalUnicodeFormat);
}
The code works as follows:
- The TextField constructor takes the text of the field.
- Name is any text, and ID a number. Both are saved with the document and identify the field later.
- CanAdd tells whether a field can be inserted at the input position; a field can't be inserted into another field. Add returns
trueif the field was inserted. - Start is the one-based position of the field's first character.
- Text fields are kept in the TX Text Control format, so the document is saved as fields.tx.
Name has no length limit, so a field can carry a larger piece of data, such as a JSON string, along with its text.
Set How Users Edit the Field
The following properties are saved with the document and take effect when a user edits it later, for example in the Document Editor:
- Editable decides whether users can change the text of the field, and Deleteable whether they can delete it. A field that isn't deleteable keeps its text editable, but a selection with the field inside can't be deleted or replaced.
- DoubledInputPosition adds a second input position in front of the first and behind the last character of the field, so that users decide whether text typed at the edge belongs to the field. It's
falseby default and alwaystruefor form fields. - HighlightMode decides when the field is shown with a colored background. With
HighlightMode.Activated, the field is highlighted while the input position is inside it, where the next typed character becomes part of the field. HighlightColor sets the color; its default is black with an alpha value of 60, a light gray.
TextField priceField = new TextField("$ 22.45")
{
Name = "Price",
DoubledInputPosition = true,
HighlightMode = HighlightMode.Activated
};
tx.TextFields.Add(priceField);
Add Hypertext Links and Bookmarks
A hypertext link points to a website or another document. A bookmark, a DocumentTarget, marks a position, and a document link points to it. The following program adds all three to one paragraph:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Text = "Terms and Conditions. The current version is published on . If you have questions, read ";
// A bookmark in front of the first character
tx.Select(0, 0);
DocumentTarget termsTarget = new DocumentTarget("terms");
tx.DocumentTargets.Add(termsTarget);
// A hypertext link behind "published on "
tx.Select(tx.Text.IndexOf("published on ") + "published on ".Length, 0);
HypertextLink website = new HypertextLink("our website", "https://www.textcontrol.com/")
{
DescriptiveText = "Text Control website"
};
tx.HypertextLinks.Add(website);
// A link to the bookmark at the end of the text
tx.Select(tx.Text.Length, 0);
tx.DocumentLinks.Add(new DocumentLink("the terms", termsTarget));
tx.Save("links.tx", StreamType.InternalUnicodeFormat);
}
The code works as follows:
Selectwith a length of 0 sets the input position, where each field is inserted. The text has a single paragraph, so a position in the string is the position in the document.- The DocumentTarget constructor takes the name of the bookmark.
- The HypertextLink constructor takes the text of the link and its target, which Target reads and changes later. DescriptiveText describes the link in accessible PDF documents.
- The DocumentLink constructor takes the text of the link and the
DocumentTargetit points to.
Find the Fields of All Text Parts
To find every field of a document, including those in headers, footers and text frames, loop through ServerTextControl.TextParts. Each text part implements IFormattedText, which has the field collections:
using TXTextControl;
LoadSettings loadSettings = new LoadSettings()
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord
};
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("Documents/sample.docx", StreamType.WordprocessingML, loadSettings);
foreach (IFormattedText textPart in tx.TextParts)
{
// MainText, TextFrame, HeaderFooter or FootnoteText
string part = textPart.GetType().Name;
foreach (ApplicationField field in textPart.ApplicationFields)
{
string parameters = field.Parameters != null ? string.Join(" ", field.Parameters) : "";
Console.WriteLine($"{part}: {field.TypeName} {parameters} = \"{field.Text}\"");
}
foreach (HypertextLink link in textPart.HypertextLinks)
{
Console.WriteLine($"{part}: link to {link.Target} = \"{link.Text}\"");
}
foreach (DocumentTarget target in textPart.DocumentTargets)
{
Console.WriteLine($"{part}: bookmark {target.TargetName}");
}
}
}
The text parts come in a fixed order: the main text first, then the text frames and then the headers and footers. For an application field, TypeName is the Word field type, such as MERGEFIELD, and Parameters holds the rest of the field code: for MERGEFIELD Address \* Upper \v, the three elements Address, \* Upper and \v.
Field Formats and Type Names
The field formats of different applications aren't compatible, so LoadSettings.ApplicationFieldFormat names the one to import. ApplicationFieldFormat has these values:
| Value | Imports |
|---|---|
None | No application fields |
MSWord | The fields of MS Word, including its legacy form fields and content controls |
MSWordTXFormFields | The form fields of MS Word as TX Text Control form fields, the other Word fields as application fields, described in Content Controls |
HighEdit | The fields of the Heiler HighEdit component in RTF documents |
LoadSettings.ApplicationFieldTypeNames limits the import to the type names you list, such as new string[] { "MERGEFIELD", "PRINTDATE" }. Besides the field names of MS Word, two groups of type names hold their settings as Office Open XML markup in Parameters rather than as switches:
| Type name | Word element | What Parameters holds |
|---|---|---|
FORMCHECKBOX, FORMDROPDOWN, FORMTEXT | The legacy form fields: check box, drop-down list and text box | The options of Word's Form Field Options dialog box |
SDTBLOCK | A content control | Its properties; the w:val attribute of the w:tag element names the kind of control: rich text, plain text, picture, combo box, drop-down list or check box |
The FormText, FormCheckBox and FormDropDown adapters and the content control adapters in Use Field Adapters for MS Word Fields read this markup for you.
Change and Remove Fields
The collections have the same methods for all kinds of fields. GetItem with an ID returns a field or null, and Remove removes a field, with or without its text. A collection can't be changed while a foreach loop runs over it, so collect the fields to remove first:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("fields.tx", StreamType.InternalUnicodeFormat);
// Change the text of a field by its name
foreach (TextField field in tx.TextFields)
{
if (field.Name == "CustomerName")
{
field.Text = "Text Control, LLC";
}
}
// Remove the field with the ID 1 and keep its text
TextField fieldWithId = tx.TextFields.GetItem(1);
if (fieldWithId != null)
{
tx.TextFields.Remove(fieldWithId, true);
}
// Collect the merge fields first, then remove them with their text
List<ApplicationField> mergeFields = new List<ApplicationField>();
foreach (ApplicationField field in tx.ApplicationFields)
{
if (field.TypeName == "MERGEFIELD")
{
mergeFields.Add(field);
}
}
foreach (ApplicationField field in mergeFields)
{
tx.ApplicationFields.Remove(field, false);
}
tx.Save("fields-changed.tx", StreamType.InternalUnicodeFormat);
}
TextFieldCollection.GetItem without a parameter returns the field at the input position. Remove with true as second parameter removes the field and keeps its text; without it, or with false, the text is removed too.
Change the Parameters of a Word Field
Parameters returns a .NET array, which has a fixed size. To add or remove a switch, build a new array and assign it to the property. The following program removes the \v switch from every merge field and sets the text the Address field shows:
using TXTextControl;
LoadSettings loadSettings = new LoadSettings()
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord
};
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("Documents/sample.docx", StreamType.WordprocessingML, loadSettings);
foreach (ApplicationField field in tx.ApplicationFields)
{
if (field.TypeName != "MERGEFIELD" || field.Parameters == null)
{
continue;
}
// A new array without the \v switch replaces the old one
if (Array.IndexOf(field.Parameters, "\\v") >= 0)
{
field.Parameters = field.Parameters.Where(p => p != "\\v").ToArray();
}
// The first parameter of a MERGEFIELD is the field name
if (field.Parameters.Length > 0 && field.Parameters[0] == "Address")
{
field.Text = "221B Baker Street, London";
}
}
tx.Save("sample-fields.docx", StreamType.WordprocessingML);
}
The code works as follows:
"\\v"in C# is the two characters\vof the Word switch. A single backslash would be the vertical tab character.WhereandToArraycreate a new array; assigning it to Parameters changes the field code.- Setting
Textchanges what the field shows, not its type or parameters.
React to Created and Deleted Fields
TextFieldCreated and TextFieldDeleted occur for fields of every class, and TextFieldEventArgs.TextField holds the field:
- Created. Names and IDs are saved and copied with a field, so a copy has the same name as the original. The handler of
TextFieldCreatedis the place to give a new field a name or ID of its own, such as "Copy of Price" for a second "Price" field. - Deleted. After a field has been deleted, only its
IDandNameare valid. Identify the removed field by them and don't read its text or position.
tx.TextFieldDeleted += (sender, e) =>
{
// Only ID and Name of a deleted field are valid
Console.WriteLine($"Field removed: {e.TextField.Name} ({e.TextField.ID})");
};
Events lists these events with the other events of ServerTextControl.
Show Field Codes
MS Word can show a field as its field code, such as { MERGEFIELD Total \# "#,##0.00" }, instead of its text. TX Text Control has no switch for this, but the code can be built from the field's TypeName and Parameters and set as the field's text. A proof copy of a template that shows every field code helps authors check field names and formats. The following program shows the codes of the merge fields in a small template, saves the proof as PDF, puts the original texts back and saves the template:
using TXTextControl;
using TXTextControl.DocumentServer.Fields;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
// A template with two merge fields
tx.Selection.Text = "Dear ";
MergeField name = new MergeField() { Name = "CustomerName", Text = "«CustomerName»" };
tx.ApplicationFields.Add(name.ApplicationField);
tx.Selection.Text = ",\r\nyour order total is ";
MergeField total = new MergeField() { Name = "Total", Text = "«Total»", NumericFormat = "#,##0.00", TextAfter = " USD" };
tx.ApplicationFields.Add(total.ApplicationField);
tx.Selection.Text = ".";
// Show the field codes and remember the field texts
List<(ApplicationField Field, string Text)> fieldTexts = new List<(ApplicationField, string)>();
foreach (ApplicationField field in tx.ApplicationFields)
{
fieldTexts.Add((field, field.Text));
field.Text = "{ " + field.TypeName + " " + string.Join(" ", field.Parameters) + " }";
}
tx.Save("template-field-codes.pdf", StreamType.AdobePDF);
// Show the field texts again
foreach ((ApplicationField field, string text) in fieldTexts)
{
field.Text = text;
}
tx.Save("template.docx", StreamType.WordprocessingML);
}
The PDF shows the two lines as Dear { MERGEFIELD CustomerName }, and your order total is { MERGEFIELD Total \f " USD" \# "#,##0.00" }.: the MergeField adapter stores the text after the field and the number format as the switches \f and \#. Changing TextField.Text changes only what the field shows; its type and parameters stay, so the restored template still contains both merge fields. For templates loaded from DOCX files, set ApplicationFieldFormat as in the section above. The blog article Toggle Field Codes in TX Text Control toggles the codes of a single field, also in the Document Editor.
Convert Fields to Plain Text
Before a document is sent to a customer, its fields can be removed while their visible text stays. Clear(true) does this for all fields of a collection:
using TXTextControl;
LoadSettings loadSettings = new LoadSettings()
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord
};
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("Documents/sample.docx", StreamType.WordprocessingML, loadSettings);
foreach (IFormattedText textPart in tx.TextParts)
{
// true removes the fields and keeps their text
textPart.ApplicationFields.Clear(true);
textPart.TextFields.Clear(true);
textPart.HypertextLinks.Clear(true);
textPart.DocumentLinks.Clear(true);
// Bookmarks have no text of their own
textPart.DocumentTargets.Clear();
}
tx.Save("sample-plain.docx", StreamType.WordprocessingML);
}
ApplicationFieldCollection.Clear and the Clear methods of the other collections take keepText as parameter. DocumentTargetCollection.Clear takes none.
Use Field Adapters for MS Word Fields
An ApplicationField only gives access to the type name, parameters and text of a Word field; the logic of the field isn't implemented. The classes of the TXTextControl.DocumentServer.Fields namespace are adapters for typical Word fields: they wrap an application field and give typed access to its settings, so you don't have to know the syntax of the field code.
- Change an existing field: pass the application field to the adapter's constructor, for example
new MergeField(applicationField). - Create a new field: create the adapter, set its properties and add its
ApplicationFieldto a collection, for exampletx.ApplicationFields.Add(mergeField.ApplicationField).
| Adapter | Field | Described in |
|---|---|---|
| MergeField | MERGEFIELD | Merge Fields |
| DateField | DATE, the current date in a format | Merge Fields |
| IfField | IF, text that depends on a comparison | Conditional Content |
| IncludeText | INCLUDETEXT, another document included in a template | Template Design |
| NextField, NextIfField | NEXT and NEXTIF, which advance to the next data record | Overview, Conditional Content |
| FormText, FormCheckBox, FormDropDown | The legacy form fields of MS Word | — |
| ContentControlFieldAdapter and its derived classes | The content controls of MS Word | Content Controls |
All adapters derive from FieldAdapter, whose ApplicationField property returns the wrapped field. The blog article Find ApplicationFields within Sections and Paragraphs in .NET C# finds the fields of a particular section or paragraph by comparing positions.
Next Steps
- Content Controls: read and fill the content controls of MS Word forms.
- Merge Fields: fill merge fields with data.
- Headers and Footers: add page number fields.
- Fields in the Document Editor: insert and change fields from JavaScript.