Wednesday, March 28, 2007

Event handler in Document Library

When working with event handlers in SharePoint, the event handlers will usually be associated with different lists. Using lists like a Task list or a Custom list and using the item adding event will present the developer with the SPItemEventProperty object as an argument. This object holds the information a developer can work with such as the ListItem property which will return the SPListItem that fired the event in question.

A problem arose when I tried making an event handler for a document library. Overriding the ItemAdding method, thus gaining access to the SPItemEventProperty, I found that this object returns a null exception. When debugging the event handler I saw that the SPItemEventProperty was in fact null. This is quite interesting since the event handlers are working on other list types.

After a few hours looking for information about this problem, non had come up with a sloution. One way to get around the problem should be to directly adress the column of interest in the listitem, like such:

  property.ListItem[columnName]

However, this I did not get to work either, still getting the nullException when running the event.

This issue  is still under investigation. If anyone has an answer, please post a repsonse.

Best regards

Sebastian

Posted by Zeb at 17:42:54 | Permanent Link | Comments (0) |

Tuesday, March 13, 2007

InfoPath 2007 and Contact Selector

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

Posted by Zeb at 13:28:46 | Permanent Link | Comments (0) |