The one aspect of InfoPath (2003) that prevented company wide deployment at my employer was the need to have the InfoPath client in order to fill out a form. Now that Microsoft has implemented Forms Server and allowed the filling of forms via a web browser, many of my colleagues have been banging at my door for custom InfoPath solutions.
The requirement that I have been presented with was to use the Contact Selector control, to make it required, and to only allow one value. After reading the above post by Ben, which references some validation code posted in a comment on the InfoPath Team blog, it became apparent there was no easy solution for browser-based forms.
Below I offer my solution:
- Domain trust form
- No digital certificate
public void InternalStartup()
{
EventManager.FormEvents.Loading +=
new LoadingEventHandler(FormEvents_Loading);
EventManager.XmlEvents["/my:myFields/my:contactSelector"].Changed +=
new XmlChangedEventHandler(contactSelector_Changed);
}
public void FormEvents_Loading(object sender, LoadingEventArgs e)
{
XPathNavigator mainDS = this.MainDataSource.CreateNavigator();
if (this.New)
{
XPathNavigator contSel =
mainDS.SelectSingleNode("/my:myFields/my:contactSelector",
NamespaceManager);
this.Errors.Add(contSel, "ContactSelectorError",
"You must select a contact.");
return;
}
}
public void contactSelector_Changed(object sender, XmlEventArgs e)
{
if (e.Site.SelectChildren(XPathNodeType.Element).Count == 1)
{
try
{
this.Errors.Delete("ContactSelectorError");
}
catch { }
}
if (e.Site.SelectChildren(XPathNodeType.Element).Count > 1)
this.Errors.Add(e.Site, "ContactSelectorError",
"Only one contact can be selected.");
if (e.Site.SelectChildren(XPathNodeType.Element).Count < 1)
this.Errors.Add(e.Site, "ContactSelectorError",
"You must select a contact.");
}
Some notes:
- "/my:myFields/my:contactSelector" is the XPath to the Contact Selector control. This is the main group, i.e. in my example, it would be:
<contactSelector>
<Person>
<DisplayName />
<AccountId />
<AccountType />
</Person>
</contactSelector> - "ContactSelectorError" is the name of the error being added/deleted. It is not displayed to the user, but rather the internal error name for code references.
- I only add the error in the loading event for new forms, since an existing form would already have these fields required. An alternative to this.New would be to test the Contact Selector control for a value, and add the error if it's value was equal to the empty string ("").
- In the function "contactSelector_Changed", you must have a try/catch around the delete statement, because if you attempt to delete an error that does not exist, an error will be thrown.
- If you have multiple contact selector controls on your form, you will need a seperate "onChanged" event for each control, and I would suggest simply changing the name of the error from "ContactSelectorError" to something like "ContactSelectorErrorEmployee", and ensure each contact selector control has a unique name for its error. You will also need as many "this.Errors.Add" lines in the loading event as you have contact selector controls you want validated.
--andrew