Visual Studio Team System (VSTS) Blog - by Neno Loje

Application Lifecycle Mangement (ALM) with Visual Studio & Team Foundation Server - since 2005

News

Recent Posts

Community

Tags

Email Notifications

VSTS Blogs

VSTS Sites

VSTS Community

My Other Blogs

German VSTS Websites

Archives

Using rich HTML descriptions instead of plain text

Objective

Allow rich HTML formatting in description fields of the MSF Agile process template.

Note: The MSF CMMI process does support HTML formatting by default. In order to use it you have to enable the formatting toolbar (see Step 6 below).

Work Item Customization

Step 1: Add a new HTML description field

Since the System.Description field is defined of type string as opposed to type HTML we need to create a new field:

2AddNewField

3AddNewField

Step 2: Change the work item layout

Use your own HTML field instead of System.Description

4EditLayout

Step 3: Refresh Work Item cache

Right-click "Work Items" in Team Explorer and select "Refresh".

5RefreshWIs

Step 4: Enable the formatting toolbar

Right-click on the Visual Studio toolbar, find and click "Formatting":

6EnableFormattingToolbar

A new toolbar will appear:

7FormattingToolbar

Result

Click into the description field and use the toolbar to format your input:

8UsingRichFormatting

 

Optional Step 5: Copying the old descriptions to the new HTML field

It would be a pity to loose the existing descriptions so let's write a small utility using the Team Foundation Object model to copy the "old" descriptions to the new HTML field:

static void CopyOldDescriptions()
{
    // TODO: Change these values:
    string tfsName = "servertogo";
    string tfsProjectName = "WorkItemCustomization";
    string tfsHtmlDescriptionFieldName = "DescriptionHtml";
    string tfsWorkItemType = "Task";

    using (TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(tfsName))
    {
        WorkItemStore wit = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
        WorkItemCollection result = wit.Query(String.Format("SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '{0}' AND [System.WorkItemType] = '{1}'", tfsProjectName, tfsWorkItemType));
        List<WorkItem> affectedWorkItems = new List<WorkItem>();
        foreach (WorkItem wi in result)
        {
            if (wi.Description.Length > 0)
            {
                // Set new description
                string value = (string)wi[tfsHtmlDescriptionFieldName];
                if (String.IsNullOrEmpty(value))
                {
                    wi[tfsHtmlDescriptionFieldName] = wi.Description.Replace("\n", "<br>");
                }
                else
                {
                    wi[tfsHtmlDescriptionFieldName] += "<br><p>Old description:</p><p>" + wi.Description.Replace("\n", "<br>") + "</p>";
                }

                // Delete old description
                wi.Description = String.Empty;

                affectedWorkItems.Add(wi);
            }
        }

        if (affectedWorkItems.Count > 0)
        {
            wit.BatchSave(affectedWorkItems.ToArray());
            MessageBox.Show("Items updated: " + affectedWorkItems.Count);
        }
        else
        {
            MessageBox.Show("Nothing to do.");
        }
    }
}

Happy formatting. :-)