SharePoint provides a handy control commonly known as a “people picker” that allows users to search for and select users defined at some specified scope. This control is normally associated with Personnel field in a SharePoint List. However, what happens when you need to add this functionality to some custom component and need to access it programmatically? It gets a lot more complicated!
This article is meant as more of a repository of knowledge that I’ve discovered while working with this control rather than a “how-to”. If you are looking for How-To articles, try these: Eric Kraus or SharePoint Tips. Likewise, please let me know if you have any additional information about the actual workings of this poorly documented control.
Where to find the control
The control is actually called a “PeopleEditor” and is in the ‘Microsoft.SharePoint.WebControls‘ namespace. You will need to add a reference to ‘Microsoft.Sharepoint.dll’ to your project in Visual Studio, which is something you probably already have if you are writing anything that works with SharePoint.
What is it?
The PeopleEditor is simply a standard UserControl with it’s own hierarchy of elements. If you were to walk the tree of controls used, you would see the structure shown below (control IDs are in green italics).
Microsoft.SharePoint.WebControls.PeopleEditor
|-System.Web.UI.HtmlControls.HtmlInputHidden (hiddenSpanData)
|-System.Web.UI.HtmlControls.HtmlInputHidden (OriginalEntities)
|-System.Web.UI.HtmlControls.HtmlInputHidden (HiddenEntityKey)
|-System.Web.UI.HtmlControls.HtmlInputHidden (HiddenEntityDisplayText)
|-System.Web.UI.WebControls.Table (OuterTable)
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.Table
|- |- |- |- |-System.Web.UI.WebControls.TableRow
|- |- |- |- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |- |- |- |-System.Web.UI.HtmlControls.HtmlGenericControl (upLevelDiv)
|- |- |- |- |- |- |-System.Web.UI.WebControls.TextBox (downlevelTextBox)
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.HyperLink (checkNames)
|- |- |- |-System.Web.UI.LiteralControl
|- |- |- |-System.Web.UI.WebControls.HyperLink (browse)
|- |- |- |-System.Web.UI.LiteralControl
|- |- |- |-System.Web.UI.HtmlControls.HtmlInputButton (CreateItem)
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.PlaceHolder
|- |- |- |- |-System.Web.UI.WebControls.Label (errorLabel)
|- |- |- |- |-System.Web.UI.WebControls.Table
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.Label
Of particular interest are upLevelDiv and downlevelTextBox as those are the controls used when a person is manually entering a name.
Developing With It
The default behavior and styling is sufficient in most cases. However, if you need to do more than the very basics with the control then I strongly recommend that you subclass it so that you can hook into the control behavior at a much deeper level. Some of the things you get with this approach are:
- Control over Formatting. Microsoft hard-codes much of the formatting in the control and buries it behind protected methods so that you can’t touch it from the outside. Microsoft applies the style between the PreRender() event but before the SaveViewState() event. In order to change the style used, you will need to override the Render() event and apply your style changes immediately before the actual control is rendered.
- OnChange event. There is none exposed but by subclassing it you can create your own and then hook into the RaisePostDataChangedEvent() method in order to raise your own.
- Access to the actual controls used. All of the controls used by the people picker are available as protected properties which means that your subclass has direct access to them without having to walk the hierarchy.
- Future Changes. By subclassing this control at the beginning and coding to your new class, you are laying the foundation so that you don’t have to redo tons of code later on in the event that you find yourself needing some of the protected behaviors.
Quirks
- Normally, you will want to work with the .Entities collection as that has the most information available about a selection but there is a great big “Gotcha” here. You need to reference .CommaSeparatedAccounts property before calling .Entities because the collection seems to only get populated after that property is referenced.
- Another Gotcha is that the control will do an Active Directory lookup of all the names you enter in .CommaSeparatedAccounts so it can be a bit of a performance hit – especially if one of those names isn’t in AD. In my environment, populating this with one valid name takes 0.1 seconds. Not much, but if you have several of these controls populated with several names then that quickly adds up to real time.
- The .Entities collection is sometimes null so you have to be careful when working with it. Given that normal development practices dictate that all public collections exist but have a .Count of zero, I have to assume that this is either developer oversight or an indication of some internal state. In either case, watch what you are doing when working with this and always check it against null before referencing properties of it.
- The RaisePostDataChangedEvent event seems to fire whenever the page is posted back a second time even if the value hadn’t changed.
- Since this is actually a SharePoint control, it expects a few things to be in place – specifically that SharePoint’s “core.js” be included on the page.
Styling the Control
Microsoft embeds the formatting for the control deep inside and then makes use of the .Style attribute rather than the .CssClass attribute which makes styling it somewhat problematic as the .Style attribute will override anything in your CSS. To make this a little bit worse, this control renders differently in IE than in other browsers like Firefox so you will have to solve styling for both browsers.
Here is what the control renders as in Internet Explorer (I’ve highlighted the key styling areas and their associated class)
Here is how it renders in Firefox. Note that the resolved user name shown is the Domain ID instead of the user name like in IE. Also, this is a simple textbox instead of the textbox/div combo that IE uses.
Tracking down what style is used where is made considerably easier with tools like the Developer Toolbar for IE and FireBug for Firefox – both free. These tools allow you to inspect page elements as they are currently rendered, showing the hierarchy of styles, controls and such. They are invaluable if you will be doing considerable tweaking to the layout of the People Picker.
Validation
There is an internal validator that allows you to validate the names entered (both on client and on Page Postback) and it works like any other validator in Asp.Net. You can enable this by setting the .ValidatorEnabled property to “True”.
It is worth noting that this is merely an implementation of the IValidator interface so it cannot be cast as one of the standard Validator types (CustomValidator, RangeValidator, etc.). This can be problematic if you are trying to work with it via the Page.Validators() collection as the IValidator interface doesn’t really provide enough information to be useful. In my case, I had to cast it as my subclassed version of the PeopleEditor control and then get the values I needed that way.
Hi.
I have a question. Is it possible to use one people-picker filed and on name selection, populate other text box.. For example. When i want to ensure consistancy in User Name Filed i use People-Picker. Also i want to poplulate another filed called User Email id. Can i user Single People Picker on sharepoint Desginer?
Hi,
I am having a issue with people picker.
Whenever i type a wrong name and try checking it the people picker shows “no exact match found” message.
When i click on the name and find the most probable match and select it still the message/error “no exact match found ” does not go away”
Ideally it should have gone away since the name is resolved now but it still shows it .
Is it a bug or there are settings that need to be corrected or is there any patch that will help us on this or in SP2 removes the problem since i have SP1 in my environment ?
Please help me on this …
you can email me at my mail id as well
Thanks,
-Vinod
OMG! Thank you so much! I’m developing a SharePoint project in C# and needed to store an email that is data from an older system with many people who no longer work with the company. Of course their name won’t validate as a SP User, so I used your information to set the display value to the old email if it fails to validate. If it validates then I set is as the controls Comma Separated accounts. I would not have known how to set the controls text visible value had it not been for your article.!
Thanks,
-Serena
I’m glad this was able to help someone as that control can be pretty quirky