TFS WIT hacks: Setting a DateTime field based on String value in another field

Posted by Stuart Preston on November 9, 2009 under Team Foundation Server | Be the First to Comment

I recently responded to a question on a Microsoft discussion list.  The question was (paraphrased):

I need to get the clock value assigned to “Field B” when the value of “Field A” is changed to a specific value.  Field A allows Yes, No values only.

I need the exact time “Field A” gets assigned Yes. When it goes back to No, I must not do anything with the value stored in “Field B”. Then if “Field A” gets assigned Yes one more time, I need “Field B” updated with the DateTime of when this assignment happened and not losing the value until next time field A gets triggered to Yes.

Well I remembered doing something similar during some prototyping on Scrum for Team System.  The initial trap is that when you set up a <COPY from=”clock” /> rule on a TFS WIT field, then Team Explorer refreshed this time after the work item is saved.  This is not the behaviour we wanted to see.  After a bit of experimentation, success!

      <FIELD name="FieldA" refname="Playground.FieldA" type="String">
        <COPY from="value" value="No" />
        <ALLOWEDVALUES>
          <LISTITEM value="Yes" />
          <LISTITEM value="No" />
        </ALLOWEDVALUES>
      </FIELD>

      <FIELD name="FieldB" refname="Playground.FieldB" type="DateTime">
        <WHEN field="Playground.FieldA" value="Yes">
          <COPY from="clock" />
        </WHEN>
        <WHEN field="Playground.FieldA" value="No">
          <READONLY />
        </WHEN>
      </FIELD>

As you can see, the trick is to deliberately set FieldB to <READONLY /> when FieldA is “No”.  I thought I’d post this here in case anyone else needs to do something similar.  A view of the history on the Work Item I edited confirms the modification works as required:

clip_image002[6]

This sample should work on TFS2005, 2008 and all versions of 2010.

TFS2010 API: Retrieving a list of Process Templates on the server.

Posted by Stuart Preston on November 7, 2009 under Team Foundation Server | 2 Comments to Read

I thought I’d post some utility code that I’ve been playing with to retrieve information about the Process Templates available on a TFS 2010 instance.

As you can see from the code, each TeamProjectCollection has its own store of Process Templates (in TFS 2008 there was in effect a single “Project Collection”) so we need to look through each collection to retrieve the templates that have been uploaded to it.

You’ll need references to Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll, Microsoft.TeamFoundation.Common.dll.  On a machine with Visual Studio 2010 installed they should be found in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0 or C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0 depending on whether you have a 64-bit version of Windows or not.  You’ll also need to set the Target Framework to .NET Framework 3.5 as the assemblies required are in the v2 GAC.

This code will work against TFS2010 Beta 2 but is not guaranteed to work in the RTM.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;

namespace TFSUtils
{
    class Program
    {
        static void Main(string[] args)
        {
            //replace this with the URL to your TFS instance.
            Uri tfsUri = new Uri("http://sptfs02:8080/tfs");

            TeamFoundationApplicationInstance tfai = new TeamFoundationApplicationInstance(tfsUri, new UICredentialsProvider());
            tfai.EnsureAuthenticated();

            ITeamProjectCollectionService collectionService = tfai.GetService<ITeamProjectCollectionService>();
            IList<TeamProjectCollection> collections = collectionService.GetCollections();

            foreach (TeamProjectCollection collection in collections)
            {
                if (collection.State == TeamFoundationServiceHostStatus.Started)
                {
                    Console.WriteLine(String.Format("\nCollection: {0}", collection.Name));
                    IProcessTemplates processTemplates = tfai.GetTeamFoundationServer(collection.Id).GetService<IProcessTemplates>();
                    TemplateHeader[] templateHeaders = processTemplates.TemplateHeaders();
                    foreach (TemplateHeader header in templateHeaders)
                    {
                        Console.WriteLine(String.Format("\t{0} {1}", header.TemplateId, header.Name));
                    }
                }
            }

            Console.WriteLine("\nPress any key to continue.");
            Console.ReadKey();
        }
    }
}