Taking the SuggestedValues rule one step further

Have you ever created a custom field on a TFS work item, that you wanted to be free form entry but save the entries so the next person can select from the previous entries.

You could write a custom control to do this also. However having a service in the back ground to manage this at the server is much easier. And does not have to be installed on each client. You first need to create a Web Service that will subscribe to TFS’s Bissubscribe.exe. There is plenty of information out there to show you the mechanics of this. Check out Ewald Hofman’s blog for the details on creating a web service to subscribe to TFS. It’s an old post but still useful, easy to understand and follow.

As an example, let’s assume the field we want to do this for on is called Requested By. Where users can select from the Developers or Business User Security groups or enter a name that is not a member of a group in TFS at all. To solve this problem we created a GlobalList called RequestedBy. Then we added a SuggestedValues rule to the field that included the Developers and Business Users groups, as well as the RequestedBy GlobalList.

The field definition looks like this.

<FIELD name="Requested By" refname="RequestedBy" type="String">
    <SUGGESTEDVALUES>
        <LISTITEM value="[Project]\Developers" />
        <LISTITEM value="[Project]\Business Users" />
        <GLOBALLIST name="RequestedBy" />
    </SUGGESTEDVALUES>
    <REQUIRED />
</FIELD>

 

If the user enters a value into the field that is not from one of the TFS groups or the globalist the web service kicks in and adds the value to the globalist. So the next user that enters that name will find them in the list and is less likely to spell the name differently than the first person.

And here is the code in the web service that accomplishes that task.

public void AddToGlobalList(WorkItemStore workItemStore, string globalList, string value)
{
    if (!string.IsNullOrWhiteSpace(value))
    {
        var globalLists = workItemStore.ExportGlobalLists();
        var node = globalLists.SelectSingleNode(
    string.Format("//GLOBALLIST[@name='{0}']/LISTITEM[@value='{1}']", globalList, value));

        if (node == null)
        {
            node = globalLists.SelectSingleNode(
        string.Format("//GLOBALLIST[@name='{0}']", globalList));
                    
            if (node != null)
            {
                var valueAttr = globalLists.CreateAttribute("value");
                valueAttr.Value = value;
                var child = globalLists.CreateElement("LISTITEM");
                child.Attributes.Append(valueAttr);
                node.AppendChild(child);
                workItemStore.ImportGlobalLists(globalLists.DocumentElement);
            }
        }
    }
}