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

Team Development and Software Quality with Microsofts ALM platform - since 2005

News

Recent Posts

Community

Tags

Email Notifications

VSTS Blogs

VSTS Sites

VSTS Community

My Other Blogs

German VSTS Websites

Archives

Getting started using Custom Work Item Controls

Since Service Pack 1 [1] we have the ability to create our own controls to display field value within a work item form which gives us great flexibility.

However there are two caveats with custom work item controls right now that aren’t solved:

  • They do not work with Web Access [2] so it’s not a choice for people that heavily rely on the web client.
  • They need to be deployed to the machine of every user accessing TFS.

Setting the stage

As an first realistic example we could make the priority field a little prettier. I mean the allowed values “1”, “2”, and “3” are not very descriptive. We don’t want to create a new field or change the values since we used this field already. So the solution would be to create a custom work item control on top of the existing values that displays something else.

I plan to create a new control that has a combobox on it and will display something nicer than the real values that are stored in the database. The complete source code is attached for reference.

1. Create the Work Item Control

A custom work item control is essentially a regular Windows Forms control. It has to derive from Control and implement IWorkItemControl.

The loading takes place in IWorkItemControl.InvalidateDatasource, the saving in IWorkItemControl.FlushToDatasource. The bold code indicates peaces that were necessary to implement my wishes. The rest is infrastructure and is repeated for every control you’ll write.

Here’s the code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Controls;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TeamSystemPro.Samples.WorkItemControls
{
    /// 
    /// Work Item Control for displaying the priority (can be 1,2, or 3 in MSF) in a more descriptive way then just showing the numbers.
    /// 
    /// 
    /// Custom controls need to derive from Control.
    /// Typically custom controls are built from UserControl.
    /// The control needs to implement IWorkItemControl.
    /// This is defined in Microsoft.TeamFoundation.WorkItemTracking.Controls.dll assembly that can be found from VS installation folder, typically ":\Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies".
    /// Add reference to that assembly and line "using Microsoft.TeamFoundation.WorkItemTracking.Controls;" in code.  
    /// How it works:
    ///   After the control is loaded, a reference to work item is passed to the control using IWorkItemControl.WorkItemDatasource property.
    ///   The control is asked to display its data using IWorkItemControl.InvalidateDatasource method.
    ///   The control is required to update any values directly in WorkItem object itself when user changes data. 
    /// 
    public partial class PriorityControl : UserControl, IWorkItemControl
    {
        private WorkItem workItem;
        private string workItemFieldName;
        private IServiceProvider serviceProvider;
        private System.Collections.Specialized.StringDictionary properties;
        private bool readOnly = false;

        public PriorityControl()
        {
            InitializeComponent();
        }

        #region IWorkItemControl Members

        /// 
        /// Raise this events before updating WorkItem object with values. When value is changed by a control, work item form asks all controls (except current control) to refresh their display values (by calling InvalidateDatasource) in case if affects other controls 
        /// 
        public event EventHandler BeforeUpdateDatasource;

        /// 
        /// Raise this event after updating WorkItem object with values. When value is changed by a control, work item form asks all controls (except current control) to refresh their display values (by calling InvalidateDatasource) in case if affects other controls 
        /// 
        public event EventHandler AfterUpdateDatasource;

        /// 
        /// Control is asked to clear its contents
        /// 
        void IWorkItemControl.Clear()
        {
            cboPriorities.SelectedIndex = -1;
        }

        /// 
        /// Control is requested to flush any data to workitem object. This usually happens during save operation or when the form is left. In most cases data will be written to workitem immediately on change and hence this will not need implementation. Some customers want a way to do operations during save, and this is the closest thing we got. If you do need a way to react to before-save & after-save events, pls let us know in forums given below and we'll consider for future revision.
        /// 
        void IWorkItemControl.FlushToDatasource()
        {
            this.BeforeUpdateDatasource(this, EventArgs.Empty);
            workItem.Fields[workItemFieldName].Value = Convert.ToString(cboPriorities.SelectedIndex + 1);
            this.AfterUpdateDatasource(this, EventArgs.Empty);
        }

        /// 
        /// Asks control to invalidate the contents and redraw. At this point, control can read from work item object and display/refresh data.
        /// 
        void IWorkItemControl.InvalidateDatasource()
        {
            if (IsInitialized())
            {
                int currentValue = (int)workItem.Fields[workItemFieldName].Value;
                cboPriorities.SelectedIndex = currentValue - 1;
            }
        }

        /// 
        /// A property bag of all attributes specified in work item form xml for this control. Custom attributes are allowed and can be used to pass parameters specific for this control from work item type xml.
        /// 
        System.Collections.Specialized.StringDictionary IWorkItemControl.Properties
        {
            get { return properties; }
            set { properties = value; }
        }

        /// 
        /// Tells the control to display in readonly mode.
        /// 
        bool IWorkItemControl.ReadOnly
        {
            get { return readOnly; }
            set { readOnly = value; OnReadOnlyChanged(); }
} /// /// Gives pointer to IServiceProvider if you intended to access Document service or VS Services. If services are not needed, do nothing in this method. /// /// void IWorkItemControl.SetSite(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } /// /// This passes reference to source work item object. Cast this object to WorkItem type. /// object IWorkItemControl.WorkItemDatasource { get { return workItem; } set { workItem = value as WorkItem; } } /// /// The field name if the control is associated with a field name in work item form xml. A custom control can be associated with 0 or 1 work item field. /// string IWorkItemControl.WorkItemFieldName { get { return workItemFieldName; } set { workItemFieldName = value; } } #endregion private bool IsInitialized() { return (!this.IsDisposed && workItem != null && !string.IsNullOrEmpty(workItemFieldName) && workItem.Fields.Contains(workItemFieldName)); } private void OnReadOnlyChanged() { cboPriorities.Enabled = !readOnly; } } }

Additionally you need to create an XML file with the .wicc extensions which contains the name of your assembly file as well as the full-qualified name (i.e. namespace and classname) of your control class:

CustomWorkItemControls5

So you have your control as well as the .wicc-file (which is necessary for registration):

CustomWorkItemControls2

2. Deploy the Work Item Control

Although you could simply copy the two files (.dll and .wicc) to the “Microsoft\Team Foundation\Work Item Tracking\Custom Controls” under Environment.SpecialFolder.CommonApplicationData (we could also use the folder unter then under Environment.SpecialFolder.LocalApplicationData), but I decided to create a new MSI setup with Visual Studio which might look like this:

CustomWorkItemControls3

3. Reference the new control in a Work Item Type

After the control is deployed just change the type attribute for the control in the work item type XML. The Type should reference the name of the .wicc-file.

CustomWorkItemControls4

Now you can import your modified work item type XML (you need to use witimport as the Process Template Editor does not support custom controls right now), refresh the cache by right-clicking the Work Items node in Team Explorer and press “Refresh”.

CustomWorkItemControls1

Further recommended reading:

  • How to use Custom Controls in Work Item Form [3]
  • Communicating between custom controls: Building parent/child controls [4]

Enjoy increasing your Work Item UI experience through custom controls!

-Neno

[1] http://msmvps.com/blogs/vstsblog/archive/2006/12/15/download-visual-studio-2005-team-suite-team-foundation-server-service-pack-1-sp1.aspx

[2] http://www.devbiz.com

[3] http://blogs.msdn.com/narend/archive/2006/10/02/How-to-use-Custom-Controls-in-Work-Item-Form.aspx

[4] http://blogs.msdn.com/narend/archive/2006/10/19/communicating-between-custom-controls-building-parent-child-controls.aspx

File Attachment: WorkItemCustomControlDemo.zip (25 KB)

Comments

Naren's Blog : How to use Custom Controls in Work Item Form said:

Pingback from  Naren's Blog : How to use Custom Controls in Work Item Form

# July 9, 2007 12:06 PM