by Ewald Hofman
10. August 2010 05:06
For the customization of the work item controls for the client are many examples. There is even a codeplex project that hosts some examples. However if you want to provide a custom work item control for Web Access, it turns out that there is only little information. In this post I will describe what I did to create the custom Web Access control.
Thanks to Guneet Umra of Avanade and Serkan Inci of Microsoft to help me out on this.
For this example I will show you how you can create a textbox that has a blue background, but you can make it as fancy as you like.
- Open Visual Studio and create a new Class library called WebControl.
- Add the references to
- C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.WebAccess.Controls\10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.WebAccess.Controls.dll
- C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.WebAccess.WorkItemTracking\10.0.0.0__b03f5f7f11d50a3a\Microsoft.TeamFoundation.WebAccess.WorkItemTracking.dll
- C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
- C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.WorkItemTracking.Controls.dll
Or you can add the following lines to your project file:
<Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Client, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Controls, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<SpecificVersion>False</SpecificVersion>
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.TeamFoundation.WebAccess.WorkItemTracking, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Microsoft.TeamFoundation.WebAccess.Controls, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<SpecificVersion>False</SpecificVersion>
</Reference>
- Create a wicc file, named BlueTextbox.wicc (for more information the wicc file, see http://msdn.microsoft.com/en-us/library/bb286959.aspx)
- Set the Build Action (in the properties window) of this file to Content (so it is included in the setup project that will be created later)
- Add the following contents to the wicc file
<?xml version="1.0" encoding="utf-8" ?>
<CustomControl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Assembly>WebControl.dll</Assembly>
<FullClassName>WebControl.BlueTextbox</FullClassName>
</CustomControl>
- Rename the Class1.cs file to BlueTextbox.cs
- Paste the following contents to the file
using System;
using System.Drawing;
using Microsoft.TeamFoundation.WebAccess.WorkItemTracking.Controls;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControl
{
public class BlueTextbox : BaseWorkItemWebControl
{
public BlueTextbox()
: base(HtmlTextWriterTag.Div)
{
}
/// <summary>
/// The textbox with the blue background
/// </summary>
public TextBox TextBox { get; set; }
/// <summary>
/// The value in the work item
/// </summary>
public string FieldValue
{
get
{
// When it has a value, return that value
if (HasValidField && Field.Value != null)
return Field.Value.ToString();
// Else return the empty string
return string.Empty;
}
set
{
// When the field is value and is editable
if (HasValidField && Field.FieldDefinition.IsEditable)
// And it is changed
if ((Field.Value != null || value != null)
&& (Field.Value == null || Field.Value.ToString() != value))
{
// Set the value in the work item
base.OnBeforeUpdateDatasource(EventArgs.Empty);
Field.Value = value;
base.OnAfterUpdateDatasource(EventArgs.Empty);
}
}
}
/// <summary>
/// The value of the textbox
/// </summary>
public string Value
{
get
{
EnsureInnerControls();
return TextBox.Text;
}
set
{
EnsureInnerControls();
TextBox.Text = value;
}
}
/// <summary>
/// Build the control
/// </summary>
public override void InitializeControl()
{
base.InitializeControl();
// Create the TextBox
EnsureInnerControls();
// Save the value when it is changed
TextBox.TextChanged += delegate { FlushToDatasource(); };
}
/// <summary>
/// Add the textbox
/// </summary>
public void EnsureInnerControls()
{
if (TextBox != null)
return;
TextBox = new TextBox { BackColor = Color.Blue };
base.Controls.Clear();
base.Controls.Add(TextBox);
}
/// <summary>
/// THe underlying data is changed. Change the contents of the TextBox accordingly
/// </summary>
public override void InvalidateDatasource()
{
base.InvalidateDatasource();
// If the field is valid
if (HasValidField)
{
// And it has a value
if (Field.Value != null)
{
// change the contents of the TextBox
Value = Field.Value.ToString();
}
else
{
// else clear the value
Clear();
}
}
else
{
// If the field is not valid, then also clear the contents of the TextBox
Clear();
}
// Ensure the control is shows correctly
ResetStyles();
}
/// <summary>
/// Ensure that the control is correctly shows (width + enabled)
/// </summary>
private void ResetStyles()
{
Width = Unit.Percentage(100);
Enabled = !ControlReadOnly && !EditorReadOnly;
}
public override void FlushToDatasource()
{
base.FlushToDatasource();
FieldValue = Value;
}
}
}
- To distribute this control, the easiest way is to create a setup project. Since the location is different for x86 and x64 the easiest way is to create two setup projects.
- First create the x64 setup project: Add a new project of type Setup Project with the name WebControlSetup.x64 (you can find the project type in the Add New Project dialog under Other Project Types –> Setup and Deployment –> Visual Studio Installer)
- Remove the User’s Desktop and the User’s Programs Menu folders
- Click on the project in the Solution Explorer and open the properties window. Change the TargetPlatform to x64
- Change the DefaultLocation of the Application Folder to [ProgramFiles64Folder]\Microsoft Team Foundation Server 2010\Application Tier\Web Access\Web\App_Data\CustomControls
- Right click on the right pane to add the Primary output of the WebControl project
- When you add the primary output also all the Microsoft.TeamFoundation dll’s are added. Those dll’s should not be installed however
- You can remove those by opening up the Detected Dependencies, select those dll’s, right click to open the context menu and choose Exclude. You will see the dll’s will be removed from the File System window
- Now also add the Content of the WebControl project
- Repeat these steps to create a x86 setup project, but now use the target folder “[ProgramFilesFolder]\Microsoft Team Foundation Server 2010\Application Tier\Web Access\Web\App_Data\CustomControls”
- You can now build the WebControl solution, and install the appropriate msi on the TFS server.
- Now change the work item type to make use of the new control. You can find information how to modify work item types at http://msdn.microsoft.com/en-us/library/ms243849.aspx
- When you change the FieldControl of the Title field in the FORMS section to BlueTextbox,
<FORM>
<Layout>
<Group>
<Column PercentWidth="80">
<Control FieldName="System.Title" Type="BlueTextbox" Label="&Title:" LabelPosition="Left" />
</Column>
you will see the following when you create a new task
- There is a nice little feature in TFS to have two separate layouts for the Windows and the Web UI: You can add the attribute Target=”Windows” or Target=”Web” to the Layouts node to show two different layouts.
<FORM>
<Layout Target="WinForms">
<Group>
<Column PercentWidth="80">
<Control Type="FieldControl" FieldName="System.Title" Label="&Title:" LabelPosition="Left" />
</Column>
<Layout Target="Web">
<Group>
<Column PercentWidth="80">
<Control Type="BlueTextbox" FieldName="System.Title" Label="&Title:" LabelPosition="Left" />
</Column>