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:
- Set your form submit event to use custom code
- Add references and using statements to Microsoft.SharePoint.dll and microsoft.office.workflow.tasks.dll
- Get a semi-colon delimited list of aliases stored within the Contact Selector by using the Contact object.
- 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.
- 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
- 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
Martin Kearn Senior Consultant Microsoft Consulting Services UK Martin.Kearn@Microsoft.com |
Comments
Anonymous
April 16, 2009
PingBack from http://asp-net-hosting.simplynetdev.com/quick-tip-storing-infopath-contact-selector-values-in-sharepoint/Anonymous
May 06, 2009
hi Martin, thanks for this tip! But I currently have a task to do exactly this the opposite way: So, there is a multi user field in a SharePoínt list and I need to prefill an InfoPath Contact Selector with the current field value. I have a Web Service that reads the SharePoint list and returns the values of the list item as secondary data source. But when I bind the persons to the contact selector only the first person is set as value. Do you have any advice how to get all users set in the contact selector? Thanks MatthiasAnonymous
May 10, 2009
In response to Matthias's comment: I have never had to do this myself, but this should be possible via code in your InfoPath form. You just need to understanding the underlying XML structure that goes behind the Contact Selector and populate it accordingly. Martin KearnAnonymous
July 13, 2009
Hi Martin, I am Quite new to working with workflows in Visual Studio and specially relating them to the infopath form. I have a form with control type as Contact Selector (which will basically be to get the email id of the user so that a Cc copy will be sent once the workflow is Started) Is it possible to get the count of the total no of user enter ed in the contact Selector. The thing is i need to get the count of the number of user key in the contact selector. Could u tell how this would be possible Thanks AditiAnonymous
July 16, 2009
will this solution work if i will try to opening this in infopath clientAnonymous
July 28, 2009
This is exactly what I have been needing...but I am having a few errors with the code (New to VS coding) The errors I get on build are:
- The name 'sSiteURL' does not exist in the current context using (SPSite site = new SPSite(sSiteURL))
- The name 'qGetItem' does not exist in the current context "qGetItem.Query = "<Where>...
- The name 'web' does not exist in the current context listitems = web.Lists[... Thanks for any help on this
Anonymous
August 24, 2009
Alternatively - If you're using a workflow attached to your list you could simply take the relevant value of the ContactSelector (forget which one specifically without looking) and copy that value into a SharePoint Person or Group field. Works for me. One thing I have extreme difficulty with is populating the other way around. How on earth do you get a Person or Group field to translate through to an InfoPath Contact Selector in such a way that it appears to have resolved the user when looking at the InfoPath form.Anonymous
September 30, 2009
Jason.. here is a link to explain. http://social.msdn.microsoft.com/Forums/en-US/sharepointinfopath/thread/60d4a4eb-6d84-4aa6-acbe-6ce56348b4a2