Customizing Contact Selector Control for Single Contact Selection

More often than not, while developing custom workflow LOB (Line of Business) applications, we come across situations where we need to develop an application feature to provide end users capability to select other users or contacts for assignment of tasks, as participants of workflow, etc. from AD (Active Directory) or User Profiles in SharePoint.

In case of InfoPath 2007 browser enabled forms, there is a very handy ActiveX control available OOB, to find more about it, read following article from InfoPath Team :

Using the Contact Selector Control

Now, just in case like me, if you find above control inept in certain scenarios where you wish to make sure that only single contact is selected by end user from AD or User Profile.

And, if you find writing code for custom UI that fetches and displays users from AD or User Profiles in SharePoint Server, is too much a task and you need some sort of workaround for this issue and still be able to use the contact selector control. Then, try adding following code to Contact Selector control's (named gpContactSelector here) Changed Event:

 

 public void gpContactSelector_Changed(object sender, XmlEventArgs e)
{
  string senderLocalName = ((XPathNavigator)sender).LocalName;

  if ( senderLocalName == "DisplayName")
  {
      XPathNavigator navigator = MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:gpContactSelector", NamespaceManager);
      if (navigator != null)
      {
          int count = navigator.SelectChildren(XPathNodeType.Element).Count;
          if (count > 1)
          {
              this.Errors.Add(navigator, "InvalidUserCount", "Can't select multiple users.");
          }
      }
  }
  else if (senderLocalName == "Person")
  {
      XPathNavigator navigator = MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:gpContactSelector", NamespaceManager);
      if (navigator != null)
      {
          int count = navigator.SelectChildren(XPathNodeType.Element).Count;
          if (count == 1)
          {
              if (Errors.Count >= 1)
              {
                  try
                  {
                      this.Errors.Delete("InvalidUserCount");
                  }
                  catch (ArgumentException)
                  {
                       // Do nothing
                  }
                  catch (Exception)
                  {
                      throw;
                  }
              }
          }
      }
  }
}

 

The code snippet shown above will add an error object in form's error collection whenever an end user selects more than one contact. This should make sure that user is not allowed to submit the form, unless, the error is resolved by end user manually, i.e. by removing all the selected contacts save one from the Contact Selector control in the UI. 

We can also automate this removal of extra contacts in code behind, and then warn end users by adding an error object in the forms error collection or by displaying a message in UI.

However, do make sure that your customer is aware of this scenario and is okay with this. Otherwise, you may find a bunch of confused end users, trying to figure out, what is happening to all those contacts they selected.

Catch in this approach is, end users are not warned until they have selected a bunch of contacts. If this becomes a major usability issue and your customer is not ready to buy in, then, IMHO only choice is creating a custom UI for contact selection.