Data Source Events


The InfoPath object model consists of objects that expose properties, methods, and events. InfoPath's programming model has two kinds of events: data source events and form events. Because InfoPath's programming model emphasizes the role of events, let's take a look at the data source events first and then consider some of the useful form events, properties, and methods of the various objects.

The number of data source events is small compared with the number of form events, but they are arguably more powerful. Typically, most of the code behind a form involves sinking data source events.

Three data source events raise sequentially in the order listed here:

  • OnBeforeChange

  • OnValidate

  • OnAfterChange

Each of these events can be raised on any data node (that is, element, attribute, or group of elements) in the data source.

Note

Although the events are always raised in this order, InfoPath does not guarantee that the events will be raised one immediately after the other. If you have a hierarchy and have event handlers for different levels in the hierarchy, for example, you might not see the events handled immediately after one another for a given data source node. You might see OnBeforeChange raise for a group first, OnBeforeChange handled next for a field, and then OnValidate for the group, and so on.


While learning about these events and their functions, keep in mind that a data source change could occur because the text in a data node was deleted, cut, pasted, dragged, dropped, or modified in some other way. Furthermore, changes are not limited to textual changes in single elements. Inserting, deleting, or replacing a section and repeating a table row or list item also trigger data source events.

Suppose that we are sinking these three events for a text node called FirstName, which is bound to a text box containing the text Jogn. If the user fixes the typo by changing the text box to John, each event for the node bound to this text box will be raised twice: once as a delete operation (the text Jogn was deleted) and once as an insert operation (the text John was inserted). You will learn how to handle these cases by examining the Operation property on the DataDOMEvent object.

Furthermore, the events will not just raise on the node that changed, but also "bubble up" on the parent node of the changed node, and on its parent, and so on until the root of the data source tree is reached.

The following sections will look at two ways to create event handlers using InfoPath. Then we will describe the purpose of the OnBeforeChange, OnValidate, and OnAfterChange events.

Creating an Event Handler

How do you create an event handler for a particular data node? Suppose that you have a mortgage application form, and you want to handle the OnBeforeChange event for the telephone number HomePhone. Using the InfoPath designer, click the drop-down button on the data node called HomePhone; choose Properties; and then click the Validation and Event Handlers tab, shown in Figure 12.7.

Figure 12.7. Selecting a data source node and showing the Properties dialog box.


From the Events drop-down list, select the OnBeforeChange event. Then click the Edit button. Visual Studio will automatically generate the appropriate event handler with the appropriate attributing. Remember that the correct attributing must be in place for InfoPath to raise an event to a particular handler. These attributes are difficult to generate by hand, which is why you should use the dialog boxes of InfoPath to create these event handlers:

<InfoPathEventHandler( _   MatchPath:="/my:myFields/my:Email/my:Address", _   EventType:=InfoPathEventType.OnBeforeChange)> _ Public Sub Address_OnBeforeChange(ByVal e As DataDOMEvent)   ' Write your code here. Warning: Ensure that the constraint you   ' are enforcing is compatible with the default value you set   ' for this XML node. End Sub 


You might want to start from a data-bound control to get to a data node for which you want to handle an event. If the data node is bound to a control, you can get to the same dialog box shown in Figure 12.7 by first double-clicking the data-bound control in the view to get to its Properties dialog box, as shown in Figure 12.8.

Figure 12.8. Selecting a control's properties to handle a data event.


Click the Data Validation button to get to the dialog box shown in Figure 12.7.

The OnBeforeChange Event

The OnBeforeChange event fires before the change is made to the underlying XML data. If you want to abort the change, the OnBeforeChange event is your only chance; by the time the OnValidate event is raised, the change has already been made to the underlying data source.

To reject the change to the data, set the ReturnStatus property of the DataDOMEvent argument e to False. When ReturnStatus is set to False, InfoPath will show an error dialog box informing the user that the change is not allowed.

Several additional useful properties are associated with the DataDOMEvent object. The Operation property returns a String set to "Delete", "Update", or "Insert". This tells you whether the user is deleting data, updating data, or inserting new data. The ReturnMessage property accepts a String that is shown in a dialog box when the change is rejected. The NewValue property returns a String for the new value of the data node that was changed. The OldValue property returns a String for the value of the data node before it was changed.

Listing 12.4 shows an OnBeforeChange event handler that validates that an e-mail address is in a valid format. In Listing 12.4, we first check the DataDOMEvent object's Operation property to make sure we are not in a delete operation. If we are in a delete operation, the NewValue property would be Nothing. Then we validate the e-mail address returned by the NewValue property by using a regular expression. If the change is not matched by our regular expression, we set ReturnStatus to False and set ReturnMessage to the message text we want InfoPath to use in the error dialog box.

Listing 12.4. An OnBeforeChange Event Handler

<InfoPathEventHandler( _   MatchPath:="/my:myFields/my:Email/my:Address", _   EventType:=InfoPathEventType.OnBeforeChange)> _ Public Sub Address_OnBeforeChange(ByVal e As DataDOMEvent)   If e.Operation = "Delete" Then ' only handle update and insert     Return   End If   Dim newEmail As String = e.NewValue.ToString()   If newEmail.Length > 0 Then     Dim emailRegEx As New Regex( _        "^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*" & _        "[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$", _        RegexOptions.IgnoreCase)     e.ReturnStatus = emailRegEx.IsMatch(newEmail)     e.ReturnMessage = "Please use a valid email address."   End If End Sub 


You cannot change the data source itself from within the event handler. You cannot set the NewValue property to a different string, for example. InfoPath locks the data source to make it read-only for the duration of the event, to prevent the scenario where one event handler attempts to change the data, triggering another change event handler that might trigger yet another change event handler, and so on. Making the data source read-only while the event sink runs prevents these "event storm" scenarios.

Note

Data source change events are fired when the form loads and the data source is first created. If you set the DataDOMEvent object's ReturnStatus property to False during this data source creation phase, the form will fail to load. Use caution when writing an OnBeforeChange event handler.


The OnValidate Event

By the time the OnValidate event raises, the new value has already been written into the data source. The most common reason to sink an OnValidate event is to implement error handling.

A form error typically is shown in an InfoPath form by a red dashed "error visual" rectangle surrounding the control. If you require that a telephone number include the area code, for example, you might use an error visual rectangle to indicate an improper format, as shown in Figure 12.9.

Figure 12.9. A data validation error shown in InfoPath with a red dashed rectangle.


Let's add error handling for telephone-number data using the OnValidate event. Listing 12.5 shows an OnValidate handler that uses some additional features of the InfoPath object model. The code uses the DataDOMEvent object's ReportError method to report data validation errors. The ReportError method takes the parameters listed in Table 12.1.

Table 12.1. Parameters Passed to the DataDOMEvent Object's ReportError Method

Parameter Name

Type

What It Does

varNode

Object

The data node to associate with the error. If this data node is bound to one or more controls, the controls might display error visuals.

bstrShortError-Message

String

The short error message is the message shown in the tooltip when the user hovers over a control that is data-bound to the data node passed to varNode.

fSiteIndependent

optional Boolean

Set to true to tell InfoPath that the error applies to all potentially matching nodes, which proves useful when you add an error to a node that is repeating, and you want to add an error to the collection of nodes instead of a particular node. If set to False, the error is associated with the specific node passed to varNode and no other.

bstrDetailed-ErrorMessage

optional String

The long error message typically has more information than the short error message and has additional troubleshooting options.

lErrorCode

optional Integer

An error code value. It is sometimes convenient to be able to give each error condition a number. Setting an error code proves particularly useful if you have an existing error reporting system whose numeric codes you want to reuse.

bstrType

optional String

Tells InfoPath how first to reveal the error, If you pass the string "modeless", InfoPath will passively alert the user via an error visual on the control. If you pass the string "modal", InfoPath will show a dialog box prompting the user with the long error message.


Listing 12.5 also illustrates the use of the XDocument object's Errors collection as an alternative way to report errors. Recall from Listing 12.2 that the code generated for the InfoPath form has cached away the XDocument object in the thisXDocument variable. The code uses the thisXDocument variable to access the XDocument object for the form. It accesses the XDocument object's Errors collection and uses the Errors collection's Add method to associate errors with the form. The arguments to the Errors.Add are very similar to those of ReportError, with three differences. First, Errors.Add has no "site-independent" option. Second, Errors.Add allows you to tag an error condition with a string parameter called bstrConditionName, as well as with an error code. This condition string is for your internal use only and does not display to the end user. Third, you can call Errors.Add at any time in any handler, but ReportError may be called only from within an OnValidate event handler.

Listing 12.5. An OnValidate Event Handler That Uses the DataDOMEvent Object's ReportError Method and the XDocument Object's Errors Collection

<InfoPathEventHandler(MatchPath:="/my:myFields/my:HomePhone", _ EventType:=InfoPathEventType.OnValidate)> _ Public Sub HomePhone_OnValidate(ByVal e As DataDOMEvent)   ' Ensure that the format is "xxx-xxx-xxxx"   If e.NewValue Is Nothing Then     Return   End If   Dim siteIndependent As Boolean = False   Dim errorCode As Integer = 0   Dim modal As String = "modal"   Dim NewPhone As String = e.NewValue.ToString   If NewPhone.Length <> 12 Then     'Tell InfoPath what node caused the error, whether the error     'is associated with this node, what the short and long error     'messages should be, and whether to produce a modal or     'modeless error dialog:     e.ReportError(e.Site, "Phone number format error", __       siteIndependent, "Expected format is xxx-xxx-xxxx.", _       errorCode, "modeless")   Else     Dim indexOfHyphen As Integer = NewPhone.IndexOf("-")     If indexOfHyphen <> 3 Then       thisXDocument.Errors.Add(e.Site, "NoExpectedHyphen", _         "No hyphen found", "Expected a hyphen after 3 digits.", _         errorCode, modal)     Else       indexOfHyphen = NewPhone.IndexOf("-", indexOfHyphen + 1)       If indexOfHyphen <> 7 Then         thisXDocument.Errors.Add(e.Site, "NoExpectedHyphen",_           "Second hyphen not found", _           "Expected a hyphen after 6 digits.", _           errorCode, modal)       End If     End If   End If End Sub 


Site Versus Source

Another thing to note in Listing 12.5 is the code passes the Site property of the DataDOMEvent object to give ReportErrors and Errors.Add the data node where the error occurred. The Site property of the DataDOMEvent object refers to the data node currently processing the validation event (that is, the data node to which the event handler is listening). The DataDOMEvent object's Source property refers to the data node that changed and triggered validation. Remember that events can bubble up from child nodes to parent nodes. If you are sinking the OnValidate event of a parent node, and the user changes a child node, the Site will refer to the parent node handling the event, and the Source will refer to the child node that triggered the event in the first place.

Note

The Site and Source properties and the Errors.Add and ReportError methods all require the domain security level.


The OnAfterChange Event

In OnBeforeChange and OnValidate events, the data source is read-only and cannot be modified by your event handler code. When can your code modify the data source? Code you write in an OnAfterChange event handler is allowed to edit the data source if InfoPath is not raising the OnAfterChange event for an undo or redo operation invoked by the user. Your OnAfterChange event handler can detect whether an undo or redo resulted in the event being raised by checking the DataDOMEvent's IsUndoRedo property.

If you directly update the data node that your event handler corresponds to, use caution; otherwise, you could create infinite recursion. Listing 12.6 shows a simple OnAfterChange event handler that directly changes the data node it is handling the event for by setting e.Site.text to a new value. It prevents recursion by first checking to see whether e.Site.text is already set to the new value. It also checks the IsUndoRedo property to make sure OnAfterChange was not raised as a result of an undo or redo.

Listing 12.6. An OnAfterChange Event Handler That Updates the Data in the Node for Which It Is Handling the OnAfterChange Event

<InfoPathEventHandler(MatchPath = "/my:myFields/my:someField", _   EventType = InfoPathEventType.OnAfterChange)> _ Public Sub someField_OnAfterChange(ByVal e As DataDOMEvent)   If (e.IsUndoRedo) Then     Return   End If   If (e.Site.text = "newFieldValue") Then     Return ' prevents recursion   End If   e.Site.text = "newFieldValue" End Sub 





Visual Studio Tools for Office(c) Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath
Visual Studio Tools for Office: Using Visual Basic 2005 with Excel, Word, Outlook, and InfoPath
ISBN: 0321411757
EAN: 2147483647
Year: N/A
Pages: 221

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net