Hi!
I was having a bit of trouble getting the Contact Selector control in InfoPath 2007 to behave the way I wanted it to. Information about getting started with the contact selector can be found on the InfoPath Team Blog, http://blogs.msdn.com/infopath/archive/2007/02/28/using-the-contact-selector-control.aspx, which is a very good post about getting up and started with the contact selector.
The problem that I had was that I wanted groups to be able to expand into the users that are members of that group. After searching the internet and asking around I found no information about this and therefor wrote a little code that made this for me.
The theory behind the code is that first get all the objects in the contact selector and look at the AccountType. If the AccountType is different from User, the object is most propably a group and must therefore be expanded. To do this, search the ad for the group in question and access the propery member of the group. For each member, make a new instance of the type you use in your contact selector and use these new objects to populate an array.
This array, containing all users that are member of the group, can then be used as a source for writing information back into the XDocument.DOM. To learn more about XDocument and DOM (Document Object Model), visit MSDN2.
The code I used also requires knowledge about XML DOM Objects and Methods, http://msdn2.microsoft.com/en-us/library/ms756180.aspx.
Please note that I was hard pressed on time when doing this and therefore the code might not be as good looking as it could be.
DirectoryEntry ad = new DirectoryEntry("LDAP://dc=filobit,dc=com");
DirectorySearcher groupSearch = new DirectorySearcher();
groupSearch.SearchScope = SearchScope.Subtree;
groupSearch.PropertiesToLoad.Add("adspath");
groupSearch.SearchRoot = ad;
groupSearch.Filter = "(&(objectCategory=group)(cn=" + dispName + "))";
SearchResultCollection groups = groupSearch.FindAll();
foreach (SearchResult sr in groups)
{
DirectoryEntry groupInstance = new DirectoryEntry(sr.Properties["adspath"][0].ToString());
Array.Resize<Person>(ref temp, temp.Length + groupInstance.Properties["member"].Count);
foreach (object user in groupInstance.Properties["member"])
{
DirectoryEntry member = new DirectoryEntry("LDAP://" + user.ToString());
Person expandedUser = new Person();
expandedUser.DisplayName = member.Properties["name"][0].ToString();
expandedUser.AccountId = "FILOBIT\" + member.Properties["sAMAccountName"][0].ToString();
expandedUser.AccountType = "User";
temp[j] = expandedUser;
j++;
}
}
This first code snippet searches the ad for the group with the name stored in dispName and in the domain filobit.com. The FindAll() method was invoked to get all groups, wildcards allowed, in the domain. The first loop loops through the searchResults and gets the group. The second loop goes through all the members of the group currently processed. The object Person is the object used in the contact selector to store the users and have the properties DisplayName, AccountId and AccountType, required by the contact selector. Each new user is stored in the temp array, which is an array of Person, resized for each group.
There is some code between the code above and the code shown below that is specific to my needs, and can not be shown here.
The next part is to write back information into the XDocument.DOM. When writing information to the DOM, the contact selector will automatically run its update function and display the correct information.
The theory here is to find a Node in the DOM that we are interested in changing. In this example, the Person object in the code snippet above are supposed to be inserted as childs to a certain node. The node in my case is given by the string status, given by an external call to the method. A reference node is set as the firstChild of the searchNode. This is to navigate to the correct node before inserting the new users. Since we do not want the group in the contact selector and all users are stored in an array, we can safely remove all childs of the node before adding our own. A new array of IXMLDOMNode is made and each element in the array is reset to the node object, kept as refence before the information in the node is set to that of a user. At last the user is appended to the DOM by calling the searchNode.appenChild() method.
IXMLDOMNode searchNode = thisXDocument.DOM.selectSingleNode("my:myFields/my:" + status);
IXMLDOMNode node = searchNode.firstChild;
while (searchNode.hasChildNodes())
{
searchNode.removeChild(searchNode.firstChild);
}
IXMLDOMNode[] newNodes = new IXMLDOMNode[expandedUsers.Length];
for (int m = 0; m < expandedUsers.Length; m++)
{
newNodes[m] = node.cloneNode(true);
newNodes[m].firstChild.text = expandedUsers[m].DisplayName;
newNodes[m].firstChild.nextSibling.text = expandedUsers[m].AccountId;
newNodes[m].firstChild.nextSibling.nextSibling.text = expandedUsers[m].AccountType;
searchNode.appendChild(newNodes[m]);
}
I hope this information was to some use.
Best regards
Sebastian