Event Handling In InfoPath

Within the InfoPath 2007, there is the option to handle events using an item called the Event Manager. Similar to the event receiver architecture provided by other facilities of SharePoint, the Event Manager provides mechanisms by which forms can provide and respond to event capturing. Writing code that is consumed by the Event Manager is done using Visual Studio Tools for Application (VSTA), and when choosing to program events off the InfoPath design surface it will attempt to open the VSTA IDE.

The Event Manager is called from the InternalStartup() method, which controls the events that are registered when a form is initially loaded. Each event that should be captured can be registered within the InternalStartup() method and then delegates can be constructed to encapsulate a reference to a method which handles the events tripped custom code.

There are several events that can be captured and managed when leveraging the Event Manager.

Event Capturing Available Through the Event Manager

Event Type
Event Capture
Action
Delegate
Control Event OnClick When a user clicks a control in InfoPath ClickedEventHandler(object sender, Microsoft.Office.InfoPath.ClickedEventArgs e)
Form Event OnSaveRequest When a user saves an InfoPath Form SaveEventHandler(object sender, Microsoft.Office.InfoPath.SaveEventArgs e)
Form Event OnContextChange When a user changes a Form Context, such as when a form is submitted SubmitEventHandler(object sender, Microsoft.Office.InfoPath.SubmitEventArgs e)
Form Event OnSign When a user signs an InfoPath form with a digital signature SignEventHandler(object sender, Microsoft.Office.InfoPath.SignEventArgs e)
Form Event OnMergeRequest When a user merges a set of InfoPath forms (merge operation) MergeEventHandler(object sender, Microsoft.Office.InfoPath.MergeEventArgs e)
Form Event OnSwitchView When an InfoPath view is changed (switch view operation) ViewSwitchedEventHandler(object sender, Microsoft.Office.InfoPath.ViewSwitchedEventArgs e)
Xml Event OnBeforeChange Before a passed XPath node is changed, wire an XML event XmlChangedEventHandler(object sender, Microsoft.Office.InfoPath.XmlEventArgs e)
Xml Event OnValidate When an XPath node is being validated, wire an XML event XmlChangingEventHandler(object sender, Microsoft.Office.InfoPath.XmlChangingEventArgs e)
Xml Event OnAfterChange After an XPath node is changed, wire an XML event XmlValidatingEventHandler(object sender, Microsoft.Office.InfoPath.XmlValidatingEventArgs e)
Registering View Delegate in InternalStartup()

Using the InfoPath event handlers is as straight-forward as the event receiver/listener architecture that is present with SharePoint content types and list definitions. The event being captured must be registered within the InternalStartup() method by standard declaration. Wiring an event to display a message box telling the user they are switching views requires registering the event first.

[csharp]

void InternalStartup(object sender, EventArgs e)   
{     
((FormControl)sender).EventManager.FormEvents.ViewSwitched +=        new ViewSwitchedEventHandler(OnSwitchView);    
}
 
[/csharp]
 

View Delegate
Once the handler has been registered within the InternalStartup() method, the event handler that it is called can be declared by a delegate.
 
[csharp]
public delegate void ViewSwitchedEventHandler(object sender,         Microsoft.Office.InfoPath.ViewSwitchedEventArgs e)  
{      
MessageBox.Show(“You are switching InfoPath Views!”);  
}
[/csharp]

With the event wired as such, whenever a user switches InfoPath views, a message box displays, confirming that they are switching views. More elegant event handlers could be developed depending on the event capturing logic that is required; however the overall concept remains the same.

By the same token, it is possible to validate the XML fields so a user entering null values into an InfoPath form is passed a message.

Register Event in InternalStartup()
First, register the XML event handler in the InternalStartup() method. Since it is an XML event, an XPath statement is required in order for InfoPath to know which control to validate against.
 
[csharp]
public void InternalStartup()
{   
EventManager.XmlEvents[“/my:myFields/my:ProSharePoint2007Field “].Validating += new XmlValidatingEventHandler(ProSharePoint2007Field_Validating);
}
[/csharp]
Once the event handler has been registered, the actual event logic can be wired to the event to be called when the XML event is tripped.
Validating a Null Value with Event Handling
Use a String.IsNullOrEmpty if check on the value being passed into the InfoPath control to verify a null entry. Otherwise, you can use the Errors.Add method in order to point each error to the XML node, or InfoPath field the error is associated with; in this case the ProSharePoint2007Field. The other error handling method in the below code is the Error.Delete method which removes the error handler if no errors are encountered in the InfoPath field. Any number of string comparison options that are available through the .NET framework could be leveraged if you’re looking for a more elegant error-checking mechanism.
 
[csharp]

public void ProSharePoint2007Field_Validating(object sender, XmlValidatingEventArgs e)

{  

if (!String.IsNullOrEmpty(e.NewValue))    

{       

Errors.Add(e.Site, “ProSharePoint2007Field “, “Null Values are not allowed!”);    

}   

else    

{       

Errors.Delete(“ProSharePoint2007Field “);    

}

}

[/csharp]

Share

EventArgs Example

In one my past posts, I talked about that CryptoCollaboration using the EventArgs base class because it keeps things nice and generalized, allowing for expanasion for the handling of future event integration. A person emailed me and asked for a practical example of when would use such a thing in a SharePoint WebPart. Eh, ok.

I am going to use an example of a progress class, that, well, as you can guess will display the progress of some sort of execution that happens with a SharePoint WebPart.

The first class is the Process Arguments class (ProcessArgs), that inherits from the EventArgs base class.

[csharp]

public class ProgressArgs : EventArgs
{
private int m_nPercentageComplete = 0;
private DataRow m_oDataRow;

public ProgressArgs(DataRow dataRow, int percentageComplete)
{
this.m_oDataRow = dataRow;
this.m_nPercentageComplete = percentageComplete;
}

public DataRow CurrentDataRow
{
get
{
return this.m_oDataRow;
}
}

public int PercentageComplete
{
get
{
return this.m_nPercentageComplete;
}
}
}

[/csharp]

In the next class, there will be the establishment of the event handler that will be called from a sister class by use of a delegate.

[csharp]

public delegate void ProgressEventHandler(object sender, ProgressArgs e);

[/csharp]

Now that the delegate is established, you can call it in some general class file.

[csharp]

public event ProgressEventHandler ProgressEvent;

protected virtual void OnProgress(ProgressArgs e)
{
if (this.ProgressEvent != null)
{
this.ProgressEvent(this, e);
}
}

[/csharp]

Then calculate out the progress.

[csharp]

ProgressArgs e = new ProgressArgs(row, (int) ((((double) num) / ((double) this.DBDataTable.Rows.Count)) * 100));
this.OnProgress(e);

[/csharp]

I am not saying that this is the only way to do it, but with applications that you plan on extending later it is the route that I have choosen to go in the past. I may at some point explore the deficiencies in a such an approach, however at this current time I just want to finish the damn thing.

Share