Quick Tip: Storing InfoPath Contact Selector values in SharePoint

Some time ago now, I published a post entitled Quick Tip: Using the SharePoint ‘Person or Group’ field in code which covered details of how to use the ‘Person or Group’ field type in your custom applications.

As I eluded to at the end of that post, one of the most common uses of the ‘Person or Group’ field in custom applications is when you are using the InfoPath Contact Selector control to select people inside an InfoPath form and want to store those values in a ‘Person or Group’ field inside SharePoint. The Contact Selector control is a very powerful control and there is lots of good information about it in these posts:

My own article: Top Tips for InfoPath form development with SharePoint: Part 1 (look for tip 4)

The InfoPath Team Blog: Using the Contact Selector Control

MSDN: The Contact Selector Control

As wonderful as the Contact Selector control is, it leaves a lot to the imagination in terms of storing its values in SharePoint and that is what this post is all about!

The scenario here is that we have a browser–based form (lets say a holiday request form) that gets saved to a SharePoint Form Library when it is submitted. Part of that form is the manager that needs to approve the request which is captured as a Contact Selector.

So the questions is “how do you save your contact selector value to SharePoint?”

But surely standard InfoPath property promotion does the trick!?

The first place I look when trying to do this was to try to promote one of the three values that the Contact Selector generates to a SharePoint ‘Person or Group’ field via InfoPath’s standard property promotion.

The short answer is this did not work. The main reason is that the Contact Selector is not a single field, it is actually 3 different fields (DisplayName, AccountId and AccountType) that are arranged in a very specific XML structure.

You could just bind one of the three fields to SharePoint but the column will be created as a standard ‘text’ type. This is because the three properties contained within the Contact Selector are all text fields in InfoPath. So this will work but it will not be stored as a ‘Person or Group’ field in SharePoint. This is great if you just need the login name, but what we really want is the value to be stored as a ‘Person or group’ field.

So what is the answer?

Regrettably, the only way to do this is to introduce custom code to your InfoPath form. However, the good news is that the code is fairly simple.

The code sample below deals with multiple values. If you only have a single person in your contact selector it would be much simpler, however this is a more robust solution.

The full code sample is below but these are the main steps:

  1. Set your form submit event to use custom code
  2. Add references and using statements to Microsoft.SharePoint.dll and microsoft.office.workflow.tasks.dll
  3. Get a semi-colon delimited list of aliases stored within the Contact Selector by using the Contact object.
  4. Get the SPLisItem for the form that was submitted. The logic for this will vary on your solution. In most cases the form has a unique ID, but for the sake of this simple example I am simply matching the Title field in SharePoint. So long as you get an SPLIstItem for the form that was submitted it doe snot really matter how you do this.
  5. Construct a string in the right format for a ‘Person or Group’ field. Refer to my Quick Tip: Using the SharePoint ‘Person or Group’ field in code article for details on this
  6. Update the Person or Group field in the list item.

The code is as follows:

using Microsoft.SharePoint;
using Microsoft.Office.Workflow.Utility;

public void FormEvents_Submit(object sender, SubmitEventArgs e)
{
//actually submit the form
e.CancelableArgs.Cancel = false;

    //get a navigator bound to the gpContactSelector
XPathNavigator xn = this.MainDataSource.CreateNavigator();
XPathNavigator xnManager = xn.SelectSingleNode("/my:myFields/my:Manager/my:gpContactSelector", this.NamespaceManager); //this is the path to the gpContactSelector for your Contact Selector control

    //get a semi-colon delimited array of aliases stored inside the contact selector
string aliases = "";
using (SPSite site = new SPSite(sSiteURL))
{
using (SPWeb web = site.RootWeb)
{
//add the login name for each person to the string
Contact[] contacts = Contact.ToContacts(xnManager.InnerXml, web);
if (contacts != null && contacts.Length > 0)
{
foreach (Contact contact in contacts)
{
if (contact != null)
{
aliases += contact.LoginName + ";";
}
}
}
//trim the final ;
if (aliases.EndsWith(";"))
{
aliases = aliases.Substring(0, aliases.Length - 1);
}
}
}

    //get the list item that was added by the form. This will depend on the logic of the form, but this simple example goes on the title
qGetItem.Query = "<Where><Contains><FieldRef Name='Title'/><Value Type='Text'>" + "some value that represents the title" + "</Value></Contains></Where>"; //replace 'some value that represents the title' with the title of your form
SPListItemCollection listitems = web.Lists["FormsLibaryDisplayName"].GetItems(qGetItem); //replace 'FormsLibaryDisplayName' with the name of your form library
SPListItem li = listitems[0];

    //construction a person field string
string personFieldString = "";
string[] aliases_a = aliases.Split(';');
foreach (string alias in aliases_a)
{
//get an SPUser from the alias
SPUser user = web.EnsureUser(alias);
//construct the person field sring from the ID and Login name. The ;# separator is the right format for a Sharepoint person or group field
personFieldString += user.ID.ToString() + ";#" + user.LoginName.ToString() + ";#";
}

    //update the list item
li["PersonFieldName"] = personFieldString; //replace 'PersonFieldName' with the name of your Person or Group field in SharePoint
li.Update();
}

That is the end of the article, I hope you found it useful.

This article was published by

MartinKearn

Martin Kearn Senior Consultant Microsoft Consulting Services UK Martin.Kearn@Microsoft.com

Click here for my bio page