Form Filling in .NET MAUI PDF Viewer (SfPdfViewer)

12 Jun 202424 minutes to read

The SfPdfViewer allows you to fill, edit, save, export, and import Acroform fields in a PDF document.

Supported form fields

You can load and fill in the following form fields in a PDF document using the PDF viewer.

  • Text box
  • Checkbox
  • Radio button
  • Combo box
  • Signature
  • List box
  • Button

Loading PDFs with XFA forms

The PDF viewer supports only Acroforms. PDF documents that contain XFA form cannot be viewed in the PDF Viewer. When a PDF with XFA form is attempted to be loaded, the PDF will not be loaded and the DocumentLoadFailed event will be raised. Refer this page to know more about handling document load failure.

private void PdfViewer_DocumentLoadFailed(object sender, DocumentLoadFailedEventArgs e)
{
    if (e.Message == "This PDF cannot be loaded because it contains XFA form.")
    {
        // Handle XFA loading failure.
    }
}

Retrieve form data from the PDF

The form data in a PDF can be obtained from the SfPdfViewer.FormFields property. The form data will be available when the PDF completes loading and the data can be retrieved from the DocumentLoaded event. The following code snippet illustrates getting the total count of form fields in the PDF document.

public void WireDocumentLoadedEvent()
{
    // Wire the document loaded event of the "SfPdfViewer" to occur when a PDF document is loaded.
    PdfViewer.DocumentLoaded += OnDocumentLoaded;
}

private void OnDocumentLoaded(object? sender, EventArgs? e)
{
    // Get the form field count.
    int fieldCount = PdfViewer.FormFields.Count;
}

Editing form fields programmatically

Editing text form fields

A text form field can be modified using the Text property. The following code snippet illustrates retrieving a text form field named “name” from PDF Viewer.

FormField formField = pdfViewer.FormFields.Where(x => x.Name == "name").FirstOrDefault();

if (formField is TextFormField nameTextBox)
{
    // Modify the text entered in the Text Box field.
    nameTextBox.Text = "Jonathan";
}

Editing checkbox form fields

By modifying the IsChecked property, the checkbox field can be checked or unchecked programmatically. The following code snippet illustrates retrieving a checkbox form field named “newsletter” from PDF Viewer.

FormField formField = PdfViewer.FormFields.Where(x => x.Name == "newsletter").FirstOrDefault();

if (formField is CheckboxFormField checkBox)
{
    // Mark the checkbox as checked.
    checkBox.IsChecked = true;
}

Editing combo box form fields

The SelectedItem property can be used to programmatically choose an item from the combo box. The SelectedItem should be one of the values from the ComboBoxFormField.Items array. The following code snippet illustrates retrieving a combobox form field named “state” from PDF Viewer.

FormField formField = PdfViewer.FormFields.Where(x => x.Name == "state").FirstOrDefault();

if (formField is ComboBoxFormField comboBox)
{
    // Select the desire item from the combo box.
    comboBox.SelectedItem = comboBox.Items[4];
}

Editing list box form fields

The SelectedItems property can be used to programmatically choose an item from the list box. The SelectedItems should contain only the values from the ListBoxFormFields.Items array. Both one and more selections are supported by the list box. The below code snippet illustrates modifying a single-select list box form field named “courses” from PDF Viewer.

FormField formField = PdfViewer.FormFields.Where(x => x.Name == "courses").FirstOrDefault();

if (formField is ListBoxFormField listBox)
{
    // Select the desire item from the list box.
    listBox.SelectedItems = new ObservableCollection<string> { listBox.Items[0] };
}

The below code snippet illustrates modifying a multi-select list box form field named “courses” from PDF Viewer.

FormField formField = PdfViewer.FormFields.Where(x => x.Name == "courses").FirstOrDefault();

if (formField is ListBoxFormField listBox)
{
    // Select the desire item from the list box.
    listBox.SelectedItems = new System.Collections.ObjectModel.ObservableCollection<string> { listBox.Items[1], listBox.Items[2], listBox.Items[3] };
}

Editing radio button form fields

Programmatically select an item from the radio buttons using the SelectedItem property. The SelectedItem should be one of the values from the RadioButtonFormField.Items array. The following code snippet illustrates retrieving a radio button form field named “gender” from PDF Viewer.

FormField formField = PdfViewer.FormFields.Where(x => x.Name == "gender").FirstOrDefault();

if (formField is RadioButtonFormField radioButton)
{
    // Select the desired item from the radio buttons.
    radioButton.SelectedItem = radioButton.Items[0];
}

Editing signature form fields

Programmatically, add a signature to an unsigned signature field by creating and assigning an ink annotation to the SignatureFormField.Signature property. The following code snippet illustrates retrieving a signature form field named “signature” from PDF Viewer.

SignatureFormField? signature = PdfViewer.FormFields.Where(x => x.Name == "signature").FirstOrDefault() as SignatureFormField;
if (signature != null)
{
    List<List<float>> inkPointsCollection = new();
    inkPointsCollection.Add(new List<float> { 10f, 10f, 10f, 20f, 20f, 20f, 30f, 30f, 30f, 40f, 40f, 40f, 50f, 60f });
    InkAnnotation inkSignature = new InkAnnotation(inkPointsCollection, signature.PageNumber);
    inkSignature.Color = Colors.Red;
    // Add the created handwritten signature to the signature form field.
    signature.Signature = inkSignature;
}

The Signature property is of type InkAnnotation and it will behave like an ink after signing. If the PDF document is saved, the signature will be preserved as an ink annotation in the saved document.

Supressing the signature modal view

The Sfpdfviewer allows you to supress the signature modal view and use your own UI in its place. This can be achieved by setting the FormFieldModalViewAppearingEventArgs.Cancel property to true in the SignatureModalViewAppearing event handler.

The below code snippet illustrates supressing the signature modal view and using a UI implemented in the app in its place. In this illustration, it is assumed that the signature is produced in the form of an image stream when the user completes drawing the signature in the custom dialog. When the signing is completed using the custom dialog, a stamp annotation is created and assigned as the signature of the form field.

SignatureFormField? signatureFormField;
pdfviewer.SignatureModalViewAppearing += PdfViewer_SignatureModalViewAppearing;

private void PdfViewer_SignatureModalViewAppearing(object? Sender, FormFieldModalViewAppearingEventArgs e)
{
    e.Cancel = true;
    signatureFormField = e.FormField as SignatureFormField;
    
    // Implement your own UI for creating a signature.
    ShowCustomDialog();
}

Private void customDialogOkButton_Clicked(object sender, EventArgs e)
{
   //Get the signature in the form of a Stream instance (possibly converted from an image of the user's free hand drawing) 
   signatureImageStream = GetSignatureImageStream();
   
   // Create a stamp annotation. The bounds values are not necessary since the stamp will be automatically fit over the signature form field. 
   StampAnnotation signatureStamp = new StampAnnotation(signatureImageStream, signatureFormField.PageNumber, new RectF(0, 0, 0, 0));
   
   signatureFormField.Signature = signatureStamp;
}

Button form fields

Button form fields will be rendered in the PDF viewer. But the PDF viewer supports only the GoTo actions that navigates to a particular location in the PDF document alone. Other types of button actions are not supported.

Adding custom information to a form field

The SfPdfViewer allows you to assign custom information to form fields. The CustomData property is utilized to store additional information about each form field instance for reference. However, it’s essential to note that these data are solely intended for reference purposes and will not be displayed in the SfPdfViewer interface.

The following code sample demonstrates how to set the CustomData property for a form field. In this code sample, we set the custom data to represent the modification time of the form field.

private void PdfViewer_FormFieldValueChanged(object sender, FormFieldValueChangedEventArgs e)
{
        e.FormField.CustomData="Modified Date is: " +DateTime.Now.ToString();
}

Restrict form field editing

The form fields can be prevented from being modified by setting the ReadOnly property. The following example illustrates how to make all form fields read-only.

// Restrict the editing of all the form fields.
foreach (FormField formField in PdfViewer.FormFields)
{
    formField.ReadOnly = true;
}

Clearing form data

The ClearFormData method will clear the data in all form fields in the PDF.

// Clear all the form field data.
PdfViewer.ClearFormData();

The ClearFormData method passed with the page number will clear all the form field data on the mentioned page of a PDF document.

// Clear all the form field data on the 2nd page.
PdfViewer.ClearFormData(2);

Events to track form field interaction

The SfPdfViewer allows you to track form field interactions using events.

Detecting the value change of form fields

The FormFieldValueChanged event will be raised when the values of the form fields are changed. The below code snippet illustrates detecting the value change of a text form field.

<syncfusion:SfPdfViewer x:Name="pdfViewer" FormFieldValueChanged="PdfViewer_FormFieldValueChanged"/>
private void PdfViewer_FormFieldValueChanged(object? sender, FormFieldValueChangedEventArgs? e)
{
    // Check whether the form field is a text field.
    if (e != null && e.FormField is TextFormField textFormField)
    {
        //Get the value of the form field after the event occurs.    
        string? newText = e.NewValue.ToString();

        //Get the value of the form field before the event occurs.
        string? oldText = e.OldValue.ToString();
    }
}

Similarly, the value changes of other form field types can also be detected using this event. The OldValue and NewValue properties should be cast to the expected type based on the type of the field. e.g. For a check box, they should be typecast to bool which indicates the checked state of the checkbox.

Detecting the focus and unfocus of form fields

The FormFieldFocusChanged event will be raised when text or signature field is focused or unfocused.

<syncfusion:SfPdfViewer x:Name="pdfViewer" FormFieldFocusChanged="PdfViewer_FormFieldFocusChanged"/>
private void PdfViewer_FormFieldFocusChanged(object? sender, FormFieldFocusChangedEvenArgs? e)
{
    if (e != null)
    {
        //Get the occurring form field.             
        FormField? field = e.FormField;
        //Get the hasFocus value of the form field.            
        bool hasFocus = e.HasFocus;
    }
}

NOTE

  • This event will be raised only for the text and signature form fields.

Import and Export form data

The SfPdfViewer allows you to import and export form data to and from PDF documents. The import and export of form data support the following file data formats:

  • XFDF
  • FDF
  • JSON
  • XML

The required file format can be chosen from the DataFormat enumeration. In the following sections, only the XFDF file format is explained for brevity.

NOTE

The XFDF and FDF are the standard file data formats that can be used across global PDF viewers. Whereas, JSON and XML are the custom formats that can only be used across the Syncfusion PDF Viewers supported on other platforms like WPF, Flutter, JavaScript, etc.

Import form data

The form data can be imported into a PDF document using the ImportFormData method. The stream of the file to be imported and the data format should be passed as parameters to the method. The following example explains how to import form data from an XFDF file, assuming that the file is in the application’s data directory.

void ImportFormData()
{
    string fileName = Path.Combine(FileSystem.Current.AppDataDirectory, "FormDataInfo.xfdf");
    Stream inputFileStream = File.OpenRead(fileName);
    inputFileStream.Position = 0;

    pdfViewer.ImportFormData(inputFileStream, Syncfusion.Pdf.Parsing.DataFormat.XFdf);
}

To ignore errors while importing a faulty file, you can pass the value true for the continueImportOnError parameter.

PdfViewer.ImportFormData(inputFileStream, Syncfusion.Pdf.Parsing.DataFormat.XFdf, true);

Export form data

The form data can be exported from a PDF document using the ExportFormData method. The empty stream to write the exported data and the data format should be passed as parameters to the method. The following code explains how to export form field data from a PDF document into an XFDF file in the application’s data directory.

void ExportFormData()
{
    // Create the target file
    string targetFile = Path.Combine(FileSystem.Current.AppDataDirectory, "ExportedFormFile.xfdf");
    FileStream fileStream = File.Create(targetFile);

    pdfViewer.ExportFormData(fileStream, Syncfusion.Pdf.Parsing.DataFormat.XFdf);
}

How to perform validation over the form field data?

In PDF viewer, form validations can be done by obtaining the values from the form fields using the FormFields property and comparing them with the expected values. Below is an example that illustrates retrieving form fields by their names and checking whether they meet the expected values, before saving the document.

In this example, the form field values are checked whether they meet the below criteria. If the criteria are satisfied, the PDF will be saved along with the form data. Otherwise, an error dialogue will be shown.

Field name Validation messages
Name * Name is required.
* Name should have at least 3 characters.
* Name should not exceed 30 characters.
* Name should not contain numbers.
* Name should not contain special characters.
Email * Email is required.
* Email should be in correct format.
Date of birth * Date of birth is required.
* Date of birth should be in dd/mm/yyyy format.
Course * Atleast one course should be selected.
Signature * Signature is required.
async void ValidateAndSaveForm()
{
    ReadOnlyObservableCollection<FormField> _formFields = PdfViewer.FormFields;

    if (_formFields == null || _formFields.Count == 0)
    {
        return;
    }

    List<string> errors = new List<string>();

    foreach (FormField formField in _formFields)
    {
        if (formField is TextFormField textFormField)
        {
            // Handle text form fields
            if (textFormField.Name == "Name")
            {
                // Validation for the 'name' field
                if (string.IsNullOrEmpty(textFormField.Text))
                {
                    errors.Add("Name is required.");
                }
                else if (textFormField.Text.Length < 3)
                {
                    errors.Add("Name should have at least 3 characters.");
                }
                else if (textFormField.Text.Length > 30)
                {
                    errors.Add("Name should not exceed 30 characters.");
                }
                else if (Regex.IsMatch(textFormField.Text, @"[0-9]"))
                {
                    errors.Add("Name should not contain numbers.");
                }
                else if (Regex.IsMatch(textFormField.Text, @"[!@#$%^&*(),.?""{}|<>]"))
                {
                    errors.Add("Name should not contain special characters.");
                }
            }
            else if (textFormField.Name == "dob")
            {
                // Validation for the 'dob' field
                if (string.IsNullOrEmpty(textFormField.Text))
                {
                    errors.Add("Date of birth is required.");
                }
                else if (!DateTime.TryParseExact(textFormField.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out _))
                {
                    errors.Add("Date of birth should be in dd/mm/yyyy format.");
                }
            }
            else if (textFormField.Name == "email")
            {
                if (string.IsNullOrEmpty(textFormField.Text))
                {
                    errors.Add("Email is required.");
                }
                else if (!Regex.IsMatch(textFormField.Text, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
                {
                    errors.Add("Email should be in correct format.");
                }
            }
        }
        else if (formField is ListBoxFormField listBoxFormField)
        {
            if (listBoxFormField.SelectedItems.Count == 0)
            {
                errors.Add("Please select at least one item from the list.");
            }
        }
        else if (formField is SignatureFormField signatureFormField)
        {
            if (signatureFormField.Signature == null)
            {
                errors.Add("Please sign in the signature field.");
            }
        }
    }

    if (errors.Count > 0)
    {
        await DisplayAlert("Errors", string.Join("\n", errors), "Try Again");
    }
    else
    {
        string fileName = Path.Combine(FileSystem.Current.AppDataDirectory, "FilledForm.pdf");
        using FileStream fileStream = File.Create(fileName);
        pdfViewer.SaveDocument(fileStream);
        await DisplayAlert("Success", "Form submitted successfully.", "OK");
    }
}