How to: Add an Event Handler Using the InfoPath 2003 Object Model

The menu commands for adding event handler functions in a form template project that is compatible with the InfoPath 2003 object model are essentially the same as those for using script. For example, in order to add an OnLoad event handler, with the form open in InfoPath design mode point to Programming on the Tools menu, and then click On Load Event. The focus automatically switches to the form code for the OnLoad event handler in the Microsoft Visual Studio Tools for Applications (VSTA) or the Microsoft Visual Studio code editor.

In managed-code form template projects, the class that contains event handler functions and the event handlers themselves are identified by attributes specific to InfoPath in the code module.

All of the following procedures assume that you have a form template project open in either Microsoft Office InfoPath 2007 with Microsoft Visual Studio Tools for Applications (VSTA), Visual Studio 2005 with Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System, or Visual Studio 2008 with Visual Studio Tools for Office.

Add an event handler for the OnClick event of a command button

  1. On the Controls task pane or the Visual Studio Toolbox, click Button to add a button to the form.

  2. Double-click the button, and then click Edit Form Code.

    The focus switches to the stub for the event handler for the OnClick event in the code editor.

Add an event handler for the OnBeforeChange, OnValidate, or OnAfterChange event of a field or group

  1. Right-click a data-entry control bound to the field or group, such as a Text Box control.

  2. Point to Programming, and then click On Validate Event.

    The focus switches to the stub for the event handler for one of the following events in the code editor: OnBeforeChange, OnValidate, or OnAfterChange.

    Note

    If you are working in Visual Studio, and you add an event handler to a field or group and then later change the schema of the data source in the InfoPath Data Source task pane in a way that affects that field or group (for example, by renaming or moving it), the following message will be displayed when you switch back to Visual Studio: "You have made changes to the schema of your form template that may require the XPath expressions in the form's code to be updated. Do you want these expressions to be updated automatically?" You should always click Yes so that the XPath expression that is used to associate your event handler with the field or group will be automatically updated to reflect your changes. If you click No, you must update the XPath expression in the MatchPath parameter of the InfoPathEventHandler attribute of your event handler yourself to prevent your event handler from failing. For more information, see "How Event Handlers are Identified" later in this topic.

    Note

    Also note that when you make a change to the schema in the Data Source task pane in InfoPath, these changes are automatically saved, overwriting your existing form template without prompting when you switch back to Visual Studio.

Add an event handler for the OnLoad, OnSwitchView, OnContextChange, or OnSign event of a form

  • On the Tools menu, point to Programming, and then click the form event that you want to write an event handler for.

    The focus switches to the stub for the event handler for one of the following in the code editor: OnLoad, OnSwitchView, OnContextChange, or OnSign.

Add an event handler for the OnSubmitRequest event of a form

  1. On the Tools menu, click Submitting Options.

  2. Select the Allow users to submit this form check box, and then click Perform custom action using Code.

  3. Click Edit Code, and then click OK.

    The focus switches to the stub for the event handler for the OnSubmitRequest event in the code editor.

Add an event handler for the OnSaveRequest event of a form

  1. On the Tools menu, click Form Options.

  2. In the Open and Save category, click Save using custom code, and then click Edit.

    The focus switches to the stub for the event handler for the OnSaveRequest event in the code editor.

Add an event handler for the OnVersionUpgrade event of a form

  1. On the Tools menu, click Form Options.

  2. In the Programming category, select Use custom event from the On version upgrade list, and then click Edit.

    The focus switches to the stub for the event handler for the OnVersionUpgrade event in the code editor.

Add an event handler for the OnMergeRequest event of a form

  1. On the Tools menu, click Form Options.

  2. In the Advanced category, select the Enable Form merging and the Merge using custom code check boxes, and then click Edit.

    The focus switches to the stub for the event handler for the OnMergeRequest event in the code editor.

Adding an Event Handler for the OnAfterImport Event

To add event handlers for the OnAfterImport event, you must open the form code for your managed-code form template and add the event handler function manually. For information on how to write an event handler for this event, click the link for the OnAfterImport event.

Adding an Event Handler for a Secondary Data Source

The following example shows how to add an event handler for a secondary data source. The example assumes a secondary data source from a resource file named books.xml, which has the following schema:

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="catalog">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="book" minOccurs="0" maxOccurs="unbounded"></xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="genre" type="xsd:string"></xsd:element>
    <xsd:element name="author" type="xsd:string"></xsd:element>
    <xsd:element name="book">
        <xsd:complexType>
            <xsd:all>
                <xsd:element ref="author" minOccurs="0" maxOccurs="1"></xsd:element>
                <xsd:element ref="title" minOccurs="0" maxOccurs="1"></xsd:element>
                <xsd:element ref="genre" minOccurs="0" maxOccurs="1"></xsd:element>
                <xsd:element ref="price" minOccurs="0" maxOccurs="1"></xsd:element>
                <xsd:element ref="publish_date" minOccurs="0" maxOccurs="1"></xsd:element>
                <xsd:element ref="description" minOccurs="0" maxOccurs="1"></xsd:element>
            </xsd:all>
            <xsd:attribute ref="id"></xsd:attribute>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="price" type="xsd:string"></xsd:element>
    <xsd:element name="title" type="xsd:string"></xsd:element>
    <xsd:element name="publish_date" type="xsd:string"></xsd:element>
    <xsd:element name="description" type="xsd:string"></xsd:element>
    <xsd:attribute name="id" type="xsd:string"></xsd:attribute>
</xsd:schema>

The form's view is built from this data source. The form code creates a hash table based on the authors and the number of books they have written. You can update an entry from the table shown in the view and the OnAfterChange event handler updates the hash table. Note that the DataObject property of the InfoPathEventHandler attribute (which is implemented by the InfoPathEventHandlerAttribute class) is used to reference the secondary data source.

namespace AuxDom
{
    // InfoPathNamespace attribute goes here.
    public class AuxDom
    {
        private XDocument thisXDocument;
        private Application thisApplication;
        private Hashtable authors;

        public void _Startup(Application app, XDocument doc)
        {
            thisXDocument = doc;
            thisApplication = app;

            authors = new Hashtable();
        }

        public void _Shutdown()
        {
            authors.Clear();
        }

        // The following function handler is created by Microsoft
        // Office InfoPath. Do not modify the type or number of
        // arguments. 
        [InfoPathEventHandler(EventType=InfoPathEventType.OnLoad)]
        public void OnLoad(DocReturnEvent e)
        {
            IXMLDOMDocument books = thisXDocument.GetDOM("books");
            DOMNodeList externalAuthors = books.selectNodes("/catalog/book/author");
            foreach (IXMLDOMNode authorNode in externalAuthors)
            {
                AddBookFromAuthor(authorNode.text);
            }
        }

        // The following function handler is created by Microsoft
        // Office InfoPath. Do not modify the type or number of
        // arguments. 
        [InfoPathEventHandler(MatchPath="/catalog/book/author", EventType=InfoPathEventType.OnAfterChange, DataObject="books")]
        public void books__author_OnAfterChange(DataDOMEvent e)
        {
            if (e.IsUndoRedo)
            {
                // An undo or redo operation has occurred and the DOM 
                // is read-only.
                return;
            }
            
            if (e.Source.text != e.NewValue.ToString())
            {
                RemoveBookFromAuthor(e.OldValue.ToString());
                AddBookFromAuthor(e.NewValue.ToString());
            }
        }

        private void AddBookFromAuthor(string authorName)
        {
            if (authors.Contains(authorName))
            {
                authors[authorName] = (int)authors[authorName] + 1;
            }
            else
            {
                authors.Add(authorName, 1);
            }
        }

        private void RemoveBookFromAuthor(string authorName)
        {
            if (authors.Contains(authorName))
            {
                authors[authorName] = (int)authors[authorName] - 1;
            }
            if ((int)authors[authorName] == 0)
            {
                authors.Remove(authorName);
            }
        }

        // The following function handler is created by Microsoft
        // Office InfoPath. Do not modify the type or number of
        // arguments. 
        [InfoPathEventHandler(MatchPath="ShowAuthors", EventType=InfoPathEventType.OnClick)]
        public void ShowAuthors_OnClick(DocActionEvent e)
        {
            // Write your code here.
            StringBuilder report = new StringBuilder();

            foreach (string authorName in authors.Keys)
            {
                report.Append(authorName + ",\t\t\t");
                report.Append(authors[authorName] + "\n");
            }

            thisXDocument.UI.Alert(report.ToString());
        }
    }
}

How the Class that Contains Event Handlers is Identified

When you create a new InfoPath form template project that is compatible with the InfoPath 2003 managed code object model, an assembly-level System.ComponentModel.Description attribute is applied to the class at the beginning of the form code module to identify the class that contains all event handlers for the form template.

Important

Do not modify the System.ComponentModel.Description attribute in this class. If you do so, your form template will not be able to identify where event handlers are located, and the event handlers will fail to run.

using System;
using Microsoft.Office.Interop.InfoPath.SemiTrust;

// Office integration attribute. Identifies the startup class for the // form. Do not modify.
[assembly: System.ComponentModel.DescriptionAttribute(    "InfoPathStartupClass, Version=1.0, Class=Template1.FormCode")]
Imports System
Imports Microsoft.Office.Interop.InfoPath.SemiTrust

' Office integration attribute. Identifies the startup class for the form. Do not modify.
<Assembly: System.ComponentModel.DescriptionAttribute( _    "InfoPathStartupClass, Version=1.0, Class=Template1.FormCode")>

How Event Handlers are Identified

When you add a new event handler using menu commands or buttons in the InfoPath design mode user interface, the stub for the event handler function is written into the form. The following example shows the stub event handler created for an OnValidate added for a field named 'total'.

[C#]

[InfoPathEventHandler(MatchPath="/invoice/total", EventType=InfoPathEventType.OnValidate)]
public void total_OnValidate(DataDOMEvent e)
{
    // Write your code here.
}

[Visual Basic]

<InfoPathEventHandler(MatchPath:="/invoice/total",EventType:= OnValidate)> Public Sub total_OnValidate(ByVal e As EventArgs)
    ' Write your code here.

End Sub

You can then add code that invokes members of the InfoPath object model using the private cached members of the thisXDocument or thisApplication variables, or by using the members accessed from the e EventArgs object received by the event handler:

[C#]

thisXDocument.UI.Alert.(e.Site.text);

[Visual Basic]

thisXDocument.UI.Alert.(e.Site.text)

The InfoPathEventHandler attribute (as defined by the InfoPathEventHandlerAttribute class) is the custom attribute for functions that will be used as event handlers.

When required by the event, the MatchPath parameter (as defined by the MatchPath property of the InfoPathEventHandlerAttribute class) specifies an XPath expression that identifies the event source. The EventType parameter (as defined by the EventType property of the InfoPathEventHandlerAttribute class) specifies the type of event. You should not change the values of these parameters. If the values of these parameters are changed, the event handler may not compile correctly, or event notification will not occur as expected.

Obfuscating Code in Event Handlers

If you run an obfuscator utility on the assembly that is generated when a managed-code form template is compiled (projectname.dll), InfoPath will not be able to load the assembly when a user opens the form. If you want to obfuscate the code for your event handlers or other form code, you must put the code that you want to obfuscate in a separate assembly, and reference that assembly in your project, and then call members of the referenced assembly from FormCode.cs or FormCode.vb. It is important that you run the obfuscator utility only on the referenced assembly.

See Also

Concepts

How to: Respond to Form Events Using the InfoPath 2003 Object Model