Thursday, September 20, 2007
Posted on Thursday, September 20, 2007 2:26:59 AM (Mountain Daylight Time, UTC-06:00)  Comments [0] | 
Categories: .NET | ArcDeveloper | Devt Tools

I'm in the process of creating a set of Visual Studio templates to share with the community - pretty simple stuff, but can be quite a time saver. In the past I've posted about how to streamline coding using templates, and while the process for packaging templates outlined in that post works, it's pretty manual, and that's not going to work if I'm going to maintain and grow these things. Enter MSBuild. But before I go into that, lets review how I've organized the solution.

The solution is called "ArcDevelper.Templates" - and it simply contains a bunch of other projects that contain the template files, as shown in the following graphic.

Template Solution Contents

Each project simply has the template file (class.cs for example), an associated icon, and the vstemplate file that tells Visual Studio how to transform the file. It's important to note that I'm are just using Visual Studio as an editing environment, and the solution as an organizational scheme - we do not actually "build" anything in the traditional sense.

First off the projects would not compile because the still have string parameters in them that get replaced when the templates are run (see my previous post on templates for more). What we want to do is package the files so they can be used as "templates" - this is where MSBuild comes in.

The MSBuild Script

The other thing I have in the solution is a build.xml file that actually extracts out the files, puts them into zip files and moves them to my "ItemTemplates" folder. With this in place, I can easily make changes to my templates, re-run the build script, and have the updated templates immediately available.

In order to make this work, I had to use MSBuild "batching", which is not exactly intuitive. Without getting into too much about MSBuild (Google it - there's ton's of info around), when creating the itemgroup that will be fed into the target (the actual zip & copy), you need to create some metadata for the items, and then use the Outputs attribute of the Target to subset the items by some of the metadata. As an old client of mine used to say - clear as mud. Maybe this will help...

  <ItemGroup>

    <Projects Include="$(SolutionDir)\csclass">

      <path>$(SolutionDir)\csclass</path>

      <zipname>CSClass</zipname>

      <itemname>Class</itemname>

    </Projects>

    <Projects Include="$(SolutionDir)\vbclass">

      <path>$(SolutionDir)\vbclass</path>

      <zipname>VBClass</zipname>

      <itemname>Class</itemname>

    </Projects>

  </ItemGroup>

This is the Item Group that lists the templates (projects) that we will be working with. The path, zipname and itemname sub-elements are the metadata I was talking about. This is then used by the target...

  <Target Name="Build" Inputs="@(Projects)" Outputs="%(Projects.ZipName)">

    <!-- Create a list of the files in the output folder-->

    <CreateItem Include="%(Projects.path)\%(Projects.itemname).*">

      <Output TaskParameter="Include" ItemName="FilesToZip" />

    </CreateItem>

    <!-- Zip the files-->

    <Zip Files="@(FilesToZip)" ZipFileName="$(BuildFolder)\%(Projects.zipname).zip"  Flatten="true"/>

  </Target>

The target specifically notes the inputs and the outputs. Apparently by specifying a metadata item in the outputs forces MSBuild to group / subset the items (depending on how you want to think about it) by that item. In my case, the item is unique - so I get the effect of simply looping over the list.

Anyhow - now I've got this all working smoothly, so I'll add some more stuff into the templates, and then load it up into the ArcDeveloper.net Subversion repository over at SourceForge. I'll post about the actual templates when they are up there.

Comments are closed.