Fields in the RadFlowDocument model are special constructions that hold data, which can change/be updated – for example page numbers or merge fields. Fields consist of field code and field result. The field code fragment defines how the field result should be calculated when the field is updated. The field result fragment holds the latest calculated result. In the model these two fragments are separated by a special type of inline – FieldCharacter. FieldCharacters are 3 types:
- Start: Defines the start of the field.
- End: Defines the end of the field.
- Separate: Separates the code and result fragments.
The inlines between the start and separate field characters form the code fragment and the inlines between the separate and end field characters form the result fragment.
Here is how simple page field looks like inside the document:
In the document object model Fields are represented by the Field abstract class, which holds references to the Start, Separate and End field characters that are related to the field.
The suggested way to insert field is to use the InsertField() method of RadFlowDocumentEditor class. It takes care of creating and inserting the code and result fragments as well as placing the appropriate field character inlines to separate them. The InsertField() method returns an instance of the FieldInfo class. It holds references to the start, separate and end field characters and also provides an API for getting the code and result fragments and updating the field.
Example 1: Create a document containing a Date field using RadFlowDocumentEditor
RadFlowDocument document = new RadFlowDocument(); RadFlowDocumentEditor editor = new RadFlowDocumentEditor(document); editor.InsertField("DATE", "«10/11/2012»");
You can also create and insert all the parts of the field manually by creating a FieldInfo instance and adding all the inlines to the document structure. Example 2 demonstrates how to achieve the same result as in Example 1.
Example 2: Create a document containing a Date field using the RadDocument model and FieldInfo
// Create a document with a paragraph. RadFlowDocument document = new RadFlowDocument(); Paragraph paragraph = document.Sections.AddSection().Blocks.AddParagraph(); // Create the field info. FieldInfo field = new FieldInfo(document); // Create and add all the inlines to the paragraph. paragraph.Inlines.Add(field.Start); paragraph.Inlines.AddRun("AUTHOR"); paragraph.Inlines.Add(field.Separator); paragraph.Inlines.AddRun("John Doe"); paragraph.Inlines.Add(field.End);
You can see that the manual approach is more verbose and prone to errors. If not all of the field characters are inserted the result is an invalid document. Using the RadFlowDocumentEditor on the other hand, guarantees that the document integrity is maintained.
RadWordsProcessing supports updating of some fields types. When a field is updated, its result fragment is replaced with the calculated result value. Also the Field property of the corresponding FieldInfo object will be initialized to an instance of a Field class that matches the recognized field type.
Here is a list of the field types that support updating:
- Formulas and Expressions (formulas and expressions begin with "=")
If the field type is not one of the above, the result will not be updated and the Field property of the FieldInfo class will be set to an instance of a CustomCodeField. The complete list of field codes and the switches for each of them can be found in the Docx specification.
Updating a single field is done with the UpdateField() method of the FieldInfo class as demonstrated in Example 3.
Example 3: Update a field
RadFlowDocumentEditor editor = new RadFlowDocumentEditor(new RadFlowDocument()); FieldInfo fieldInfo = editor.InsertField("DATE \@ dd/MM/yyyy", "«result»"); Console.WriteLine(fieldInfo.GetResult()); // Output: result fieldInfo.UpdateField(); Console.WriteLine(fieldInfo.GetResult()); // Output: 06/06/2014
Note that field result is not automatically updated upon insertion. The initial result fragment is passed as a parameter to the InsertField() method.
All fields in the document can be updated using UpdateFields() of RadFlowDocument. Example 4 shows how to use this method.
Example 4: Update all fields in a document
RadFlowDocument document = new RadFlowDocument(); RadFlowDocumentEditor editor = new RadFlowDocumentEditor(document); FieldInfo fieldInfo = editor.InsertField("DATE \@ dd/MM/yyyy", "«result»"); Console.WriteLine(fieldInfo.GetResult()); // Output: result document.UpdateFields(); Console.WriteLine(fieldInfo.GetResult()); // Output: 06/06/2014
In R3 2022 the above fields were introduced. Their evaluation requires calculating the size of the document elements. This is why to update them you need to provide an implementation of a NumberingFieldsProvider which can provide the needed layout logic. In the default implementation we are using the the layout logic from the RadPdfPRocessing library. To use it you need to add reference to the following assembly:
You can register the provider with the following code:
Example 5: Register the default NumberingFieldsProvider
FlowExtensibilityManager.NumberingFieldsProvider = new NumberingFieldsProvider();
The syntax of a field code is as follows:
|field-type [field-argument] [switches]|
field-type: The type of the field. For example: HYPERLINK.
argument: The argument of the field. This is optional as some of the fields do not require an argument.
switches: One or several additional properties of the field.
The syntax of a switch is the following:
| Syntax | | :--- | | \switch-character [switch-argument] |
switch-character: Character defining the switch. For example, the "\o" switch for HYPERLINK fields defines the tooltip switch.
switch-argument: The argument of the switch. The argument is optional as not all switches require an argument.
Below is an example of field code:
Fields can also be nested in each other. If there are nested fields inside the code fragment of a field – their result will be used when calculating the result of the outer field.
Example 5 creates a field, which will be evaluated to appropriate greeting based on the time of the day.
Example 6: Create a nested field
RadFlowDocumentEditor editor = new RadFlowDocumentEditor(new RadFlowDocument()); // Create an outer field with empty code fragment. FieldInfo outerFieldInfo = editor.InsertField(string.Empty, "if field result"); // Move the editor after the field start character. editor.MoveToInlineEnd(outerFieldInfo.Start); // Create a code fragment with a nested TIME field. editor.InsertText("IF "); editor.InsertField("TIME \@ HH", "time field result"); editor.InsertText(" < 12 \"Good morning!\" \"Good afternoon!\""); outerFieldInfo.UpdateField(); Console.WriteLine(outerFieldInfo.GetResult()); // Output: Good afternoon!
When calling the UpdateField() method all nested fields inside the code fragment of the field are also be updated. This is also true when using the UpdateFields() method of RadFlowDocument.
FieldInfo is the main entry point when working with fields. It serves as "glue" between the start, separate and end field characters of a field. Each field character also holds a reference to its FieldInfo class through the FieldInfo property.
The only way to create FieldCharacter is by creating FieldInfo instance. To preserve the document integrity all field characters should be inserted and removed from the document together. If the RadFlowDocumentEditor class is used for insertion – this is done automatically.
FieldInfo exposes several properties and methods for working with fields:
- Start: A reference to the Start field character.
- Separator: A reference to the Separator field character.
- End: A reference to the End field character.
- IsLocked: Specifies if the field is locked. Locked fields are not updated.
- IsDirty: Specifies if the field should be updated before it is displayed. This property is useful when creating a document and you want to assure the field is updated when the document is opened by an application.
- UpdateField(): Recalculates the field result fragment and updates the Field property.
- GetCode(): Gets the current code fragment as a string.
- GetResult(): Gets the current result fragment as a string.
Field: Gets the current Field object (e.g. DateField) associated to the field info. Note, that this property is updated every time the field is updated.
When exporting documents to DOCX format you can use the IsDirty property of an individual fields or the AutoUpdateFields property of the export settings of the DocxFormatProvider, which will cause the consumer to update the fields when the document is opened. More information about the export settings of the provider is available here.