Well, I have just joined the auspicious ranks of Team System MVP’s, now numbering 73 worldwide. You can see my profile on the MVP site. My name will now appear along side Mitch Denny and Tiago Pascoal. Wow… I have a lot to aspire to…
I should really thank Tiago Pascoal as I have a sneaky suspicion that he was the one that nominated me :) Thanks Tiago…
This Award needs to be renewed yearly, so there is much work to do…
Microsoft has just announced that the two products, Visual Studio Team Edition for Database Developers and Visual Studio Team Edition for Developers as been combined.
From today if you Own either version in 2005 or 2008 flavours you will also have access to the other.
Good stuff :)
I have a little custom control I need added to my Visual Studio Team System projects. This control will allow specific groups of users as representatives of Advocacy groups with in the life cycle model to sign off a Requirement or Change Request from within Visual Studio.
But, just to make things a little more fun, I wanted to create the custom work item tracking control using WPF.
In order to do this you need a wrapper control that allows you to load any WPF control that inherits from IWorkItemControl.
Here is an example WPF Work Item Control:
[Get SignOffControl.xaml.vb source] [Get full source] [Get latest full source]
1: Imports Microsoft.TeamFoundation.WorkItemTracking.Client
2: Imports Microsoft.TeamFoundation.WorkItemTracking.Controls
3: 'Imports Microsoft.VisualStudio.TeamFoundation.WorkItemTracking
4:
5: Namespace SignOff
6:
7: Partial Public Class SignOffControl
8: Implements IWorkItemControl
9:
10: #Region " IWorkItemControl "
11:
12: Public Event AfterUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.AfterUpdateDatasource
13: Public Event BeforeUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.BeforeUpdateDatasource
14:
15: Protected m_serviceProvider As IServiceProvider = Nothing
16: Protected m_workItem As WorkItem = Nothing
17: Protected m_workItemFieldName As String = Nothing
18: Protected m_properties As System.Collections.Specialized.StringDictionary
19:
20:
21: Public Property [ReadOnly]() As Boolean Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.ReadOnly
22: Get
23: Return Me.IsEnabled
24: End Get
25: Set(ByVal value As Boolean)
26: Me.IsEnabled = value
27: End Set
28: End Property
29:
30: Public Sub SetSite(ByVal serviceProvider As System.IServiceProvider) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.SetSite
31: m_serviceProvider = serviceProvider
32: End Sub
33:
34: Public Property WorkItemDatasource() As Object Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.WorkItemDatasource
35: Get
36: Return m_workItem
37: End Get
38: Set(ByVal value As Object)
39: If value Is Nothing And Not m_workItem Is Nothing Then
40: RemoveHandler m_workItem.FieldChanged, AddressOf OnFieldChanged
41: End If
42: m_workItem = value
43: If Not m_workItem Is Nothing Then
44: AddHandler m_workItem.FieldChanged, New WorkItemFieldChangeEventHandler(AddressOf OnFieldChanged)
45: End If
46: End Set
47: End Property
48:
49: Public Property WorkItemFieldName() As String Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.WorkItemFieldName
50: Get
51: Return m_workItemFieldName
52: End Get
53: Set(ByVal value As String)
54: m_workItemFieldName = value
55: End Set
56: End Property
57:
58: Public Property Properties() As System.Collections.Specialized.StringDictionary Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.Properties
59: Get
60: Return m_properties
61: End Get
62: Set(ByVal value As System.Collections.Specialized.StringDictionary)
63: m_properties = value
64: End Set
65: End Property
66:
67: Public Sub Clear() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.Clear
68:
69: End Sub
70:
71: Public Sub FlushToDatasource() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.FlushToDatasource
72:
73: End Sub
74:
75: Public Sub InvalidateDatasource() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.InvalidateDatasource
76:
77: End Sub
78:
79: #End Region
80:
81:
82: Protected Sub OnFieldChanged(ByVal sender As Object, ByVal e As WorkItemEventArgs)
83:
84: End Sub
85:
86: End Class
87:
88: End Namespace
It does not yet do anything, but the base wrapper is there. The visual elements only contain a couple of button to get me started testing the wapper and to make sure that the control is displayed:
[Get SignOffControl.xaml source] [Get full source] [Get latest full source]
1: <UserControl x:Class="SignOff.SignOffControl"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="317" Height="46">
4: <StackPanel>
5: <Button>SignOff</Button>
6: <Button>Clear</Button>
7: </StackPanel>
8: </UserControl>
This will display 2 buttons, but does nothing.
You then need to create your wrapper control. This is a forms control that has the Element Host forms control to host the button. I have gone down the generic rout to minimise the amount of code I would use to create an individual “stub” when creating multiple controls.
here is an example “stub” which is created as a simple class:
[Get SignOffHostControl.vb source] [Get full source] [Get latest full source]
1: Namespace SignOff
2:
3: Public Class SignOffHostControl
4: Inherits WitCustomControlBase(Of SignOffControl)
5:
6: End Class
7:
8: End Namespace
note: although this inherits from user control you will not be able to view it in the designer because of the generic nature of its inheritance. This is OK and does not hamper development.
All the heavy lifting for this control is done in the WitCustomControlBase and the generic type passed needs to meet the requirements of New, UIElement and IWorkItemControl. This ensures that it is a WPF control that inherits from IWorkItemControl.
To create this control you need to create a new Windows Forms control and call it WitCustomControlBase. Add a WPF “Element Host” to it and make that host dock to the total area.
Then we need to make the designer generic.
[Get WitCustomControlBase.Designer.vb source] [Get full source] [Get latest full source]
1: Imports Microsoft.TeamFoundation.WorkItemTracking.Client
2: Imports Microsoft.TeamFoundation.WorkItemTracking.Controls
3:
4: <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
5: Partial Class WitCustomControlBase(Of TWitWpfCustomControl As {New, UIElement, IWorkItemControl})
6: Inherits System.Windows.Forms.UserControl
7:
8: 'UserControl overrides dispose to clean up the component list.
9: <System.Diagnostics.DebuggerNonUserCode()> _
10: Protected Overrides Sub Dispose(ByVal disposing As Boolean)
11: Try
12: If disposing AndAlso components IsNot Nothing Then
13: components.Dispose()
14: End If
15: Finally
16: MyBase.Dispose(disposing)
17: End Try
18: End Sub
19:
20: 'Required by the Windows Form Designer
21: Private components As System.ComponentModel.IContainer
22:
23: 'NOTE: The following procedure is required by the Windows Form Designer
24: 'It can be modified using the Windows Form Designer.
25: 'Do not modify it using the code editor.
26: <System.Diagnostics.DebuggerStepThrough()> _
27: Private Sub InitializeComponent()
28: Me.uxElementHost = New System.Windows.Forms.Integration.ElementHost
29: Me.uxWitWpfCustomControl = New TWitWpfCustomControl
30: Me.SuspendLayout()
31: '
32: 'uxElementHost1
33: '
34: Me.uxElementHost.Dock = System.Windows.Forms.DockStyle.Fill
35: Me.uxElementHost.Location = New System.Drawing.Point(0, 0)
36: Me.uxElementHost.Name = "uxElementHost"
37: Me.uxElementHost.Size = New System.Drawing.Size(222, 72)
38: Me.uxElementHost.TabIndex = 0
39: Me.uxElementHost.Text = "uxElementHost"
40: Me.uxElementHost.Child = Me.uxWitWpfCustomControl
41: '
42: 'WitCustomHostCOntrol
43: '
44: Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
45: Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
46: Me.Controls.Add(Me.uxElementHost)
47: Me.Name = "WitCustomHostCOntrol"
48: Me.Size = New System.Drawing.Size(222, 72)
49: Me.ResumeLayout(False)
50:
51: End Sub
52: Friend WithEvents uxElementHost As System.Windows.Forms.Integration.ElementHost
53: Friend WithEvents uxWitWpfCustomControl As TWitWpfCustomControl
54:
55: End Class
As you can see the only changes that have been made are to the class to add the generic type (line 5) and to the type used on the control instance (lines 29, 53).
note: Once you have made these and the following changes to the designer, you will no longer be able to view the designer in VS because we have made modifications for the designer.
Now we have changed the designer, we need to move on to the main control code and change it to pass all calls and implementation of the IWorkItemControl interface to the WPF control.
[Get WitCustomControlBase.vb source] [Get full source] [Get latest full source]
1: Imports Microsoft.TeamFoundation.WorkItemTracking.Client
2: Imports Microsoft.TeamFoundation.WorkItemTracking.Controls
3: 'Imports Microsoft.VisualStudio.TeamFoundation.WorkItemTracking
4:
5:
6: Public Class WitCustomControlBase(Of TWitWpfCustomControl As {New, UIElement, IWorkItemControl})
7: Implements IWorkItemControl
8:
9: #Region " IWorkItemControl "
10:
11: Public Event AfterUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.AfterUpdateDatasource
12: Public Event BeforeUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.BeforeUpdateDatasource
13:
14: Public Property [ReadOnly]() As Boolean Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.ReadOnly
15: Get
16: Return Me.uxWitWpfCustomControl.[ReadOnly]
17: End Get
18: Set(ByVal value As Boolean)
19: Me.uxWitWpfCustomControl.[ReadOnly] = value
20: End Set
21: End Property
22:
23: Public Sub SetSite(ByVal serviceProvider As System.IServiceProvider) Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.SetSite
24: Me.uxWitWpfCustomControl.SetSite(serviceProvider)
25: End Sub
26:
27: Public Property WorkItemDatasource() As Object Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.WorkItemDatasource
28: Get
29: Return Me.uxWitWpfCustomControl.WorkItemDatasource
30: End Get
31: Set(ByVal value As Object)
32: Me.uxWitWpfCustomControl.WorkItemDatasource = value
33: End Set
34: End Property
35:
36: Public Property WorkItemFieldName() As String Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.WorkItemFieldName
37: Get
38: Return Me.uxWitWpfCustomControl.WorkItemFieldName
39: End Get
40: Set(ByVal value As String)
41: Me.uxWitWpfCustomControl.WorkItemFieldName = value
42: End Set
43: End Property
44:
45: Public Property Properties() As System.Collections.Specialized.StringDictionary Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.Properties
46: Get
47: Return Me.uxWitWpfCustomControl.Properties
48: End Get
49: Set(ByVal value As System.Collections.Specialized.StringDictionary)
50: Me.uxWitWpfCustomControl.Properties = value
51: End Set
52: End Property
53:
54: Public Sub Clear() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.Clear
55: Me.uxWitWpfCustomControl.Clear()
56: End Sub
57:
58: Public Sub FlushToDatasource() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.FlushToDatasource
59: Me.uxWitWpfCustomControl.FlushToDatasource()
60: End Sub
61:
62: Public Sub InvalidateDatasource() Implements Microsoft.TeamFoundation.WorkItemTracking.Controls.IWorkItemControl.InvalidateDatasource
63: Me.uxWitWpfCustomControl.InvalidateDatasource()
64: End Sub
65:
66: #End Region
67:
68: Private Sub uxWitCustomControl_AfterUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Handles uxWitWpfCustomControl.AfterUpdateDatasource
69: RaiseEvent AfterUpdateDatasource(sender, e)
70: End Sub
71:
72: Private Sub uxWitCustomControl_BeforeUpdateDatasource(ByVal sender As Object, ByVal e As System.EventArgs) Handles uxWitWpfCustomControl.BeforeUpdateDatasource
73: RaiseEvent BeforeUpdateDatasource(sender, e)
74: End Sub
75:
76: End Class
This control implements the IWorkItemControl and it is the control that Work Item Tracking loads. Work Item Tracking form display module does not know anything about WPF and we are just faking up the interface to allow us to use the full functionality on WPF in place of Windows Forms. We can use the same method to implement the other features like IWorkItemUserAction.
We then need a Work Item Custom Control (WICC) definition file.
[Get SignOffControl.wicc source] [Get full source] [Get latest full source]
1: <?xml version="1.0"?>
2: <CustomControl xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3: <Assembly>Hinshelwood.WitCustomControls.dll</Assembly>
4: <FullClassName>Hinshelwood.WitCustomControls.SignOff.SignOffHostControl</FullClassName>
5: </CustomControl>
This is the file that tells Visual Studio what to do.
This file and the .dll need to copied to the …\Application Data\Microsoft\Team Foundation\Work Item Tracking\Custom Controls\9.0\ folder.
We can now add this control to a work item by modifying the XML definition of a Work item. To test I have just replaced an existing control.
You can add this using the Power Tools process template editor.
The result?
You will notice that this control is marked as read-only, but not bad for a first pass…
It seams as if they went well! The plan of under preparing and over delivering worked a treat... Because I know the topics the lack of a prepared script allowed me to concentrate more on emparting knowlage and less on keeping to a set of arbitrary notes the go to pot as soon as the first question is asked.
Yes the presentations were a little disjointed, but the content was delivered without too much hesitation and none of the stage fright that mared my last presentation at MS... even with a laptop that had a mind of its own and kept backing through the slides as if it did not want me to go on...
It helped that the Developer Platform guys are a lot less scary than the Application Developer Consultants ;)
What's this "Developer TS VSTS" thing anyway?Well, it has a lot more sales focus that I thought it did! This is not a bad thing, but I thought that there would be some development and problem solving in there, but it is more of a pre-sales technology consultancy role... I think that this could be a good move for me, and definatly suits my personality, but I would really miss the development...
We will see, I should here by early next week...
I am doing a presentation this afternoon on Application Lifecycle Management (ALM). This is the first time that I have ever presented on this topic, and I found out that I was doing it on Friday!
I have put together a bunch of slides pulling information mostly from Wikipedia. I have another presentation afterwards on Visual Studio Team System (VSTS), but it is the ALM one that scares me. I already had canned slides for
Visual Studio Team System, but ALM is something that I have really only begun to get a handle on. I know enough to know that I do not really know anything at all :)
So why am I doing it?
Well, if you are involved with
TFS in the UK you will probably know, or have heard of Neil Kidd. He is the current UK "Developer TS
Visual Studio Team System" at Microsoft. I have delt with him both at events and in the context of work, and I have found him knowledgeable, helpful and patient, even when I ask stupid questions.
I had heard that he was moving to another area within Microsoft (I think something to do with the TFS Rangers), but I was surprised when one of the guys (thanks Jon) I have delt with at Microsoft over the years gave me a call and asked if I would be interested in the "Developer TS
Visual Studio Team System" position... Wow, an internal recomenation...
So here I am, on an easyjet flight on my way to London.
And I now return to the topic of this post, I do waffle so...
The reason the ALM presentation is making me anxious is quite apart from my fledgling knowlage on the subject, my slides are terrible! No really... They are so bad even I have trouble following them, or even coming up with a story behind them.
I am going to have to use my slides as vague pointers and try to create a presentation on the fly...bad I know, but it is the best decision out of a bad bunch. I have an hour interview before the presentation so maybe I can do some limiting of the expectations. The second presentation on
Visual Studio Team System should go a little better...I hope...
If you are going for an interview at Microsoft make sure you lock yourself away for however amount of preperation time you need, with no distractions! That means no Tv, Xbox, children, wifes, family events of any kind. Preferably you should go to a cabin in the mountins with only your internet connection to keep you company... ;) Wish me luck....
{Rant}
I think that it would be good to remove the drop down to select your blog from the main blog writing page.
I tapped it by mistake when I was trying to select a piece of text and lost my whole post...
Only 10 minutes of time, but an entire train of thought!
{Rant}
As I am traveling today and I am not taking a laptop, I want to be able to do a little personal work from my mobile..
What I would realy like is to be able to monitor and edit my
CodePlex (Team Foundation Server) work items from my phone! And I am not talking about some crappy web based solution, I hate not being able to work offline, but a Smart Client application like the one I am using now (Diarist 2) that can let me work away with cached work items and then sync later!
If only the
TFS API, excellent though it is, could be used without the need for Team Explorer to be installed.
I received a confusing error from MS Build on Friday. I assumed that it was a GDR version issue for the top level message:
Now, we have the situation with our Business Intelligence system where we have 2 solutions. One for Visual Studio 2005 projects that consist solely of the Business Intelligence Package bits, and a 2008 solution which consists of everything else that is needed to build our solution. We do plan to move everything over to 2008, but we are currently targeting SQL Server 2005.
The problem looks like it is to do with the 2008 solution an not the 2005 one:
But, the error message implies that it is the 2005 solution:
c:\Working\Xxxxx\XXX Integration (Main)\Sources\XXX\DEV\Main\XXX2005.sln(0,0): warning MSB4126: The specified solution configuration "Release|Any CPU" is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties blank to use the default solution configuration.
C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamData\Microsoft.Data.Schema.SqlTasks.targets(58,5): error MSB4018: The "SqlBuildTask" task failed unexpectedly.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.VisualStudio.TeamSystem.Data.Tasks.TaskHostLoader.Load(ITaskHost providedHost)
at Microsoft.VisualStudio.TeamSystem.Data.Tasks.DbBuildTask.Execute()
at Microsoft.Build.BuildEngine.TaskEngine.ExecuteInstantiatedTask(EngineProxy engineProxy, ItemBucket bucket, TaskExecutionMode howToExecuteTask, ITask task, Boolean& taskResult)
After reading up, I am none the wiser, but I did find information that implied that installing SP1 for TFS should fix the problem and not require that I update the TFS server. We are using GDR bits, so I will be installing GDR 16 and the SQL Server 2008 Business Intelligence bits.
UPDATE: So after jut updating the GDR, I got the solution to build! Not sure why there was an error in the 2005 solution!
Sources:
http://ozgrant.com/2008/02/28/testcontainer-in-team-build-2008-doesnt-work-for-load-tests-or-web-tests/
This is not isolated to GDR, but seams to exist in Data Dude as well. If you create the following SQL:
1: CREATE VIEW [dbo].[v_SomeView] AS
2: SELECT [BH].[Col1],
3: [BH].[Col2],
4: [BH].[Col3],
5: [BH].[Col4],
6: [BH].[Col5],
7: CASE WHEN [BHPP].[OtherCol1] IS NULL THEN -1 ELSE 1 END As [Col6],
8: CASE WHEN [BHPP].[OtherCol1] IS NULL THEN 'Not Applicable' ELSE 'PowerPack' END As [Col7],
9: CASE WHEN [BHPP].[OtherCol1] IS NULL THEN [BH].[Col5] ELSE [BHPP].[OtherCol2] END As [Col8]
10: FROM [dbo].[Table1] as [BH]
11: LEFT JOIN (SELECT [OtherCol1], [OtherCol2], [OtherCol3]
12: FROM [$(CMD)].[dbo].[Table2]
13: WHERE [OtherCol1] <> -1) as [BHPP]
14: ON [BH].[Col2] = [BHPP].[Col2]
And add it to your Database project, but using proper table names :) You will get the following error for every use of [BHPP]:
Error 13 SR0029 : Microsoft.Validation : View: [dbo].[v_SomeView] contains an unresolved reference to an object. Either the object does not exist or the reference is ambiguous because it could refer to any of the following objects:....
This is a show stopper for us as we can't (without good cause) be creating more views just to do a derived table...
I have submitted a Bug, so vote as you like, but please vote...
Bug: GDR - derived tables
Well we have been having a few problems with the GDR. Essentially when we import our database it complains about dependencies.
We have many stored procedures that call stored procedures that call stored procedures! This seams to give the GDR fits. Maybe we are doing something that we are not supposed to, but SQL does not complain.
I tried uninstalling the GDR, but that left me with NO data dude :(
SO I have reinstalled and will try again....
The Sticky Buddy has been updated to fix the following problems:
This means that if you run TFS Sticky Buddy from now you should get v1.6.
I don't as our Proxy is a bit crap and does not detect the changes in .application files for a few days :(
If you were worried about your pages viewing correctly in IE8 Beta 1 you had to restart your browser to enable "IE7 Compatibility mode". Now it is easy:
![]()