New version of Visual WIP available

A new alfa version of Visual WIP is now available for download here.

MainWindow 2011-02-28

The main window with an image column added. The Proposed and Active columns are refreshing asynchronously and a progress spinner is shown.

What’s new

Async updates of columns.

Now every column updates on a separate thread to minimize Visual WIP to freeze when updating.

When a column is first created the progress indicator is not show. This will be fixed.

New ImageColumn

ImageColumnSettings

The image column settings window

Added tools to assist in visualizing a work items age

If a work item has changed the work item border background will change color:

Has changed Border background color
within 1 min Red
between 1-2 min Yellow
between 2-5 min Green
over 5 min Transparent

The age of work item since it was created date sets an icon on the work item:

Work item age Icon
between 5-10 days 109_AllAnnotations_Info_32x32_72
between 10-20 days 109_AllAnnotations_Warning_32x32_72
over 20 days 109_AllAnnotations_Error_32x32_72

To change the behavior of this functionality the WorkItemResources.xaml has to be modified.

Recent opened files are tracked

Moved configuration to settings file

Moved the DI container configuration of IWorkItemProvider and IWorkItemProviderViewModel to the settings file unity.xml

Bug fixes

Fixed problem with hierarchical TFS queries that returned the same work item more than once.

Fixed problem when trying to resize outside of the board area

Advertisement

How to build ClickOnce applications with TeamBuild for multiple environments

  

In ths post I will show how to build ClickOnce applications with TeamBuild for multiple environments in Team Foundation Server.

I have been trying to build ClickOnce applications in our TeamBuild for some time now and only after long ours of googling and trial and error was I successful. The most useful information I found on this blog:

Publish ClickOnce project with Team Build?

Made some modifications and refactoring and here are the code we currenlty use:

This is how you call the ClickOnce build from you TeamBuild project file (line breaks added for readability):

    <Msbuild
          Projects="$(SolutionRoot)ConfigFilesBuildClickOnce.targets"
          Targets="BuildClickOnce"
          Properties="SourceDir=$(SourceDir);PublishDir=$(PublishDir);                      ClickOnceAppName=$(ClickOnceAppName);ClickOnceExeFile=$(ClickOnceExeFile);                      ClickOnceProduct=$(ClickOnceProduct);Company=$(Company);                      ClickOnceDescription=$(ClickOnceDescription);ClickOnceUrl=$(ClickOnceUrl);                      VersionNumber=$(VersionNumber);SigningCert=$(SigningCert);                      SigningCertPassword=$(SigningCertPassword)"
            />

For every environment or configuration change you want you use this. Below you find the BuildClickOnce.targets file (line breaks added for readability):

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildExtensionsPath)MicrosoftVisualStudioTeamBuildMicrosoft.TeamFoundation.Build.targets" />
    <Import Project="$(MSBuildExtensionsPath)MSBuildCommunityTasksMSBuild.Community.Tasks.Targets"/>
    <Import Project="$(MSBuildExtensionsPath)MicrosoftSDCMicrosoft.Sdc.Common.tasks"/>

    <Target Name="BuildClickOnce" DependsOnTargets="">

        <PropertyGroup>
            <ClickOnceApplicationUrl>$(ClickOnceUrl)$(ClickOnceAppName).application</ClickOnceApplicationUrl>
            <AppPublishDir>$(PublishDir)</AppPublishDir>
            <SdkPath>C:Program FilesMicrosoft SDKsWindowsv6.0A</SdkPath>
        </PropertyGroup>

        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Message="Buildning $(ClickOnceAppName) ClickOnce version: $(VersionNumber)">
            <Output TaskParameter="Id" PropertyName="StepId" />
        </BuildStep>

    <CallTarget Targets="UpdateWebPage" />

        <!--
  ************************************************
  Generate application manifest
  ************************************************
  -->
        <Exec
        Command="mage.exe -New Application -TrustLevel FullTrust                  -ToFile &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                  -Name &quot;$(ClickOnceAppName)&quot; -Version &quot;$(VersionNumber)&quot;                 -FromDirectory &quot;$(AppPublishDir)&quot;"
        WorkingDirectory="$(SdkPath)Bin"/>

        <!--
  ************************************************
  Signing application manifest
  ************************************************
  -->
        <Exec Condition="'$(SigningCertPassword)'==''"
          Command="mage.exe -Sign &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                    -CertFile &quot;$(SigningCert)&quot;"
          WorkingDirectory="$(SdkPath)Bin"  />

        <Exec Condition="'$(SigningCertPassword)'!=''"
            Command="mage.exe -Sign &quot;$(AppPublishDir)$(ClickOnceExeFile).manifest&quot;                      -CertFile &quot;$(SigningCert)&quot; -Password &quot;$(SigningCertPassword)&quot;"
            WorkingDirectory="$(SdkPath)Bin"/>

        <!--
  ************************************************
  Renaming source files to .deploy
  ************************************************
  -->
        <ItemGroup>
            <SourceFilesToRename Include="$(AppPublishDir)***.*"                  Exclude="$(AppPublishDir)*.manifest;$(AppPublishDir)*.htm"/>
            <SourceFilesToDelete Include="$(AppPublishDir)***.*"                  Exclude="$(AppPublishDir)*.application;$(AppPublishDir)*.manifest;$(AppPublishDir)*.htm"/>
        </ItemGroup>

        <Copy
            SourceFiles="@(SourceFilesToRename)"
            DestinationFiles="@(SourceFilesToRename->'$(AppPublishDir)%(RecursiveDir)%(Filename)%(Extension).deploy')"
        />

        <Delete Files="@(SourceFilesToDelete)"/>


        <!--
  ************************************************
  Generating deployment manifest
  ************************************************
  -->

        <GenerateDeploymentManifest
          MapFileExtensions="true"
          AssemblyName="$(ClickOnceAppName).application"
          AssemblyVersion="$(VersionNumber)"
          MinimumRequiredVersion="$(VersionNumber)"
          DeploymentUrl="$(ClickOnceApplicationUrl)"
          Description="$(ClickOnceDescription)"
          Product="$(ClickOnceProduct)"
          Publisher="$(Company)"
          SupportUrl="$(SupportUrl)"
          EntryPoint="$(AppPublishDir)$(ClickOnceExeFile).manifest"
          Install="true"
          UpdateEnabled="true"
          UpdateMode="Foreground"
          OutputManifest="$(PublishDir)$(ClickOnceAppName).application"/>

        <!--
  ************************************************
  Signing application manifest
  ************************************************
  -->
        <Exec Condition="'$(SigningCertPassword)'==''"
            Command="mage.exe -Sign &quot;$(PublishDir)$(ClickOnceAppName).application&quot;                     -CertFile &quot;$(SigningCert)&quot;"
            WorkingDirectory="$(SdkPath)bin"/>
        <Exec Condition="'$(SigningCertPassword)'!=''"
            Command="mage.exe -Sign &quot;$(PublishDir)$(ClickOnceAppName).application&quot;                     -CertFile &quot;$(SigningCert)&quot; -Password &quot;$(SigningCertPassword)&quot;"
            WorkingDirectory="$(SdkPath)bin"/>


        <!--
  ************************************************
  Generating Bootstrapper
  ************************************************
  -->
        <ItemGroup>
            <BootstrapperFile Include="Microsoft.Net.Framework.2.0">
                <ProductName>Microsoft .NET Framework 2.0</ProductName>
            </BootstrapperFile>
        </ItemGroup>

        <GenerateBootstrapper
          ApplicationFile="$(ClickOnceAppName).application"
          ApplicationName="$(ClickOnceAppName)"
          ApplicationUrl="$(ClickOnceUrl)"
          BootstrapperItems="@(BootstrapperFile)"
          Culture="en"
          FallbackCulture="en-US"
          CopyComponents="true"
          Validate="false"
          Path="$(SdkPath)Bootstrapper"
          OutputPath="$(PublishDir)"/>


        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Id="$(StepId)"
          Status="Succeeded"/>

        <OnError ExecuteTargets="MarkBuildStepAsFailed" />
    </Target>

    <!--
  ************************************************
  Marks a buildstep as failed
  ************************************************
  -->
    <Target Name="MarkBuildStepAsFailed">
        <BuildStep
          TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
          BuildUri="$(BuildUri)"
          Id="$(StepId)"
          Status="Failed"/>
    </Target>

    <!--
  ************************************************
  Updating web page
  ************************************************
  -->
    <Target Name="UpdateWebPage">
        <ItemGroup>
            <WebPage Include="$(PublishDir)publish.htm" />
        </ItemGroup>

        <RegEx
          Condition="Exists(@(WebPage))"
          Path="@(WebPage)"
          RegularExpression="#VERSION#"
          NewValue="$(VersionNumber)"
          Force="true"/>
    </Target>
</Project>