TX Text Control .NET for Windows Forms

Reading Form Fields and Values

Topic

A PDF form that comes back filled in carries data: a name, a selected country, a check mark. Forms.GetAcroFormFields reads this data from the PDF file or from a byte array, without loading the document into the editor. A Windows Forms application can show the values, store them or put them back into its own form, for example to let a clerk check and correct what a customer entered.

The examples read form-filled.pdf, the form of Create a PDF Form with its fields name, country and newsletter, after a user filled it in and saved it in a PDF reader. How such forms are created is described in Creating AcroForms.

How GetAcroFormFields Reads a Form

Forms.GetAcroFormFields is a static method of the TXTextControl.DocumentServer.PDF namespace, introduced in version 29.0. One overload takes the path of a PDF file, the other the PDF as a byte array. It returns an array of FormField objects of the TXTextControl.DocumentServer.PDF.AcroForms namespace, each of the class that fits its field:

ClassField in the PDFValue
FormTextFieldText field; also the date form fields of TX Text ControlValue: the text entered
FormCheckBoxCheck boxIsChecked
FormRadioButtonRadio button, derived from FormCheckBoxIsChecked
FormChoiceFieldThe base class of combo boxes and list boxesValue: the selected item; Options: all items
FormComboBoxCombo box or drop-down list, derived from FormChoiceFieldValue
FormListBoxList box, derived from FormComboBoxValue
FormButtonPush buttonNone

Every field has these members of the base class:

  • FieldName is the name the author of the form gave the field, for TX Text Control forms the Name of the form field.
  • AlternateFieldName is the alternate name, which PDF readers show as the tooltip.
  • FieldType is Tx for a text field, Btn for a button, Ch for a choice field or Sig for a signature field.
  • Bounds is the rectangle of the field in the document.

GetAcroFormFields reads forms filled in and saved with Adobe Acrobat Reader or with Google Chrome since version 85. A user of Chrome saves the filled form with the Download button, choosing the version with the changes:

A PDF form in Google Chrome with the company name filled in and the drop-down list of countries opened.

Show the Values of a Filled Form

The following code in Form1.cs collects the values of a PDF form by field name and shows them after the user picked the file:

private Dictionary<string, string> ReadFormValues(string path)
{
    Dictionary<string, string> values = new Dictionary<string, string>();

    foreach (AcroForms.FormField field in Forms.GetAcroFormFields(path))
    {
        switch (field)
        {
            case AcroForms.FormTextField textField:
                values[field.FieldName] = textField.Value;
                break;

            case AcroForms.FormCheckBox checkBox:          // check boxes and radio buttons
                values[field.FieldName] = checkBox.IsChecked ? "true" : "false";
                break;

            case AcroForms.FormChoiceField choiceField:    // combo boxes and list boxes
                values[field.FieldName] = choiceField.Value;
                break;
        }
    }

    return values;
}

private void readFormButton_Click(object sender, EventArgs e)
{
    using (OpenFileDialog dialog = new OpenFileDialog() { Filter = "PDF forms|*.pdf" })
    {
        if (dialog.ShowDialog() != DialogResult.OK)
        {
            return;
        }

        Dictionary<string, string> values;

        try
        {
            values = ReadFormValues(dialog.FileName);
        }
        catch (FilterException exception)
        {
            MessageBox.Show("The form could not be read: " + exception.Reason);
            return;
        }

        if (values.Count == 0)
        {
            MessageBox.Show("The PDF document has no form fields.");
            return;
        }

        MessageBox.Show(string.Join("\n", values.Select(value => value.Key + ": " + value.Value)));
    }
}

Form1.cs needs these using directives:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using TXTextControl;
using TXTextControl.DocumentServer.PDF;
using AcroForms = TXTextControl.DocumentServer.PDF.AcroForms;

The code works as follows:

  • The alias AcroForms separates the classes of the PDF from the form fields of the document, because both namespaces have a class named FormField.
  • The switch statement tests FormCheckBox for check boxes and radio buttons and the base class FormChoiceField for combo boxes and list boxes, because the program needs only their values. To tell the derived classes apart, test FormRadioButton before FormCheckBox and FormListBox before FormComboBox.
  • The indexer of the dictionary keeps the last value when a name occurs more than once in the array, where ToDictionary would throw.
  • A file that isn't a readable PDF throws a FilterException. GetAcroFormFields takes no password, so the fields of a PDF that requires a password to open can't be read.

For the form of Getting Started, the message shows lines such as name: Tim Typer, country: Germany and newsletter: true.

Put the Values Back Into the Form

TX Text Control doesn't write values into an existing PDF. To continue with the values in your application, load your own document of the form, the one the PDF was created from, into textControl1 and transfer the values into its form fields:

private void fillEditorFormButton_Click(object sender, EventArgs e)
{
    Dictionary<string, string> values = ReadFormValues("form-filled.pdf");

    // The main text, headers, footers and text frames
    foreach (IFormattedText textPart in textControl1.TextParts)
    {
        foreach (FormField formField in textPart.FormFields)
        {
            if (string.IsNullOrEmpty(formField.Name) ||
                !values.TryGetValue(formField.Name, out string value) || value == null)
            {
                continue;
            }

            switch (formField)
            {
                case CheckFormField checkFormField:
                    checkFormField.Checked = value == "true";
                    break;

                case SelectionFormField selectionFormField:
                    // -1 selects nothing if the value isn't one of the items
                    selectionFormField.SelectedIndex = Array.IndexOf(selectionFormField.Items, value);
                    break;

                case TextFormField textFormField:
                    textFormField.Text = value;
                    break;
            }
        }
    }
}

The code works as follows:

  • TextControl.TextParts contains the main text, the headers and footers and the text frames, each with its own FormFields collection.
  • Each form field type takes the value through its own property: Checked for check boxes, SelectedIndex of the Items for selection fields and Text for text form fields.
  • Date form fields are left out: their value arrives as the text the form displayed. To set one, parse the text with the culture of the form and assign DateFormField.Date.

Saved again as PDF, the document is a new fillable form with the values; flattened first, it is a document with fixed values, as Exporting Interactive and Flattened Forms shows. Instead of setting each field, you can also merge the values with MailMerge and FormFieldMergeType.Preselect, as Merge Form Fields describes.

Next Steps