Thursday, August 18, 2011

Creating Simple Form Item Template for VS 2008

In this For Work blog entry, I am going to create a Visual Studio Item Template for a Windows Form. We have several patterns of forms that we need to create over and over again. I want to be able to create my own Form with all my setting set by default, include some standard controls and derive from my base class, etc.

I am not using Export Template because I want to see all the working parts.

The Process

Create a Starter Form

Create a form that has everything I want in my template in a WinForm project. In this case I will pretend that we created a WinForm called MyForm.cs.

Gather the Template Files together

I created a directory somewhere on the file system and copy the form’s source files into that directory. Add to those files an ico file and a new text files with a .vstemplate extension. So for my template, I would put the following files”

MyForm.cs The Form’s code file. Not yet changed, will replace class name and namespace later.
MyForm.Designer.cs The Form’s designer code files. Will also need replace class name and namespace.
MyForm.resx (Optional) Form’s resources, In this example, I use this to set a different icon.
BICYCLE.ICO The Icon file that appears in the Add New Item dialog
MyFormCS.vstemplate Empty file. Will be the Template metadata file.

Add/Replace Template Parameters in Source files

In the process Template Parameters are substituted with values created by the New Item Wizard when the new item is created. They are declared in the form of $parameter$

In my demo, I use the following Template Parameters:

rootnamespace The full namespace of the item; “root” namespace suggests something different
safeitemrootname The name of the item (or class) being created.

So given the following code:

using System; using System.Windows.Forms; namespace ItemTemplatePlayGround { public partial class MyForm : Form { public MyForm() { InitializeComponent(); } …

I change the code to read:

using System; using System.Windows.Forms; namespace $rootnamespace$ { public partial class $safeitemrootname$ : Form { public $safeitemrootname$() { InitializeComponent(); }  

Fill out the .vstemplate file

The .vstemplate file contains most the metadata that Visual Studio needs use my template. Things like the name and description of the template, the icon that is displayed in the new New Item dialog, the project type, etc. It also contains a list of all the files that make up the templates and instructions on how to handle them. (NOTE: the physical location of the template file determines the Template’s “Language” and “Category”, so I can’t claim that it contains all the metadata).

Notice that Template Parameters appear in the .vstemplate file.

<VSTemplate Type="Item" Version="2.0.0" 
            xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <Name>My Lame Form</Name>
    <Description>An empty Form</Description>
    <DefaultName>MyForm.cs</DefaultName>
    <ProjectType>CSharp</ProjectType>
    <Icon>BICYCLE.ico</Icon>
  </TemplateData>
  <TemplateContent>
    <ProjectItem TargetFileName="$fileinputname$.cs"  
                 ReplaceParameters="true" 
                 SubType="Form">MyForm.cs</ProjectItem>
    <ProjectItem TargetFileName="$fileinputname$.Designer.cs"  
                 ReplaceParameters="true">MyForm.Designer.cs</ProjectItem>
    <ProjectItem TargetFileName="$fileinputname$.Designer.resx"
                 ReplaceParameters="true">MyForm.Designer.resx</ProjectItem>
  </TemplateContent>
</VSTemplate>

I have chosen not to go over every detail of the .vstemplate file. There are denser articles on the web that cover them in painful detail.

The TempateData section gives data about the template as a whole. Name and Description are what you think they are. DefaultName is used to propose a name in the Add New Item dialog. ProjectType is the language of the item; either CSharp or VisualBasic. Icon refers to the icon (.ico) file that provides the icon next to the project type name in the New Item dialog.

The TemplateContent contains ProjectItem elements for each of the files in the template (except the icon file and the .vstemplate itself). If your project contains 5 files total, there should be 3 ProjectItem elements.

Within the ProjectItem element, the TargetFileName attribute is the name of the new file created by the template. ReplaceParameters determines if Template Parameters in this file are replaced. SubType determines the Visual Studio Editor used to design this file; you only need this attribute if this file uses a designer. The Element’s inner text represents the name of the file within the template itself. The element value is the before file name and the TargetFileName is the after.

Where are my template files?

The default your item template files are located in My Documents\Visual Studio 2008\Templates\ItemTemplates\Language. On my system, Visual Studio 2008 was looking in C:\Users\jacks\Documents\Visual Studio 2005\Templates\ItemTemplates. So, it is a good idea to make sure that Visual Studio is looking in the right place.

To check/change the template location: Tools => Options, select the Projects and Solutions group and the General tab.

Links

Finished Template

Saturday, July 23, 2011

Generate several files from one template with the T4 Toolbox

I have been playing with using T4Toolbox to generate more than one file from a single template within Visual Studio.

T4Toolbox.Template

The Template class is the T4Toolbox’s version of TextTransformation that has a very special method called RenderToFile(); this method writes the text to be generated to a file. So, If I wanted to generate a file for each item in a list (say a list of database tables), I could use a foreach loop to create a new instance of my Template class and call Its RenderToFile method with different file names.

<#@ template language="C#v3.5" hostSpecific="true" #>
<#@ output extension="txt" #>
<#@ include file="T4Toolbox.tt" #>
<#
    Write("This file (minimum.txt) is also generated");
    for (int i = 7; i <= 11; ++i)
    {
        string fileName = string.Format("file{0:00}.lam", i);
        var lt = new LameFileTemplate(fileName);
        lt.RenderToFile(fileName);
    }
#>
<#+
private class LameFileTemplate : Template
{
    public LameFileTemplate(string fileName)
    {
        this.FileName = fileName;
    }
    private string FileName {get; set;}
    public override string TransformText()
    {
        #><#=this.FileName#><#+
        return this.GenerationEnvironment.ToString();
    }
}
#>

When I save this file, Visual Studio runs the template and creates several files. Notice that creates a file that matches the file name of the template; this can’t be helped. Since the default output extension is “cs”, it is important to set this to something else.

image
My template and generated files

NOTE: In a failed demo that I gave at the Portland Code camp this spring I wrote a template that would create a SELECT stored procedure for each table in a given database (each in its own file). The demonstration was too complicated and hard to follow. It used the Generator class SMO and a bunch of other stuff.

Thursday, June 23, 2011

The GAX Property Directive

One of the things that really bother me about T4 templates is the lack of direct parameter support (at least in the Visual Studio 2008/.NET 3 timeframe).

In an earlier post, I passed parameter by writing the parameter data to a file outside of the template and reading the data from within. I used a common assembly linked to both sides of the divide. This works for me, but it is really hacky.

GAX Template Host

During my preparation for my Portland Code Camp presentation, I came across Guidance Automation Toolkit for Visual Studio 2008. It has its own TemplateHost that includes a Dictionary of parameters.

Parameters are exposed to the Template through a custom directive. On the template, the parameter is declared using a directive like this:

<#@ property processor="PropertyProcessor" name="MyName" type="String" #>
The directive contains the following parts:
processor Should be "PropertyProcessor" (there may be a way to write your own processor, I haven’t gone down that rat hole yet).
name The Variable name that can appear in your code. It works just like a variable, however, tangable T4 Editor doesn’t provide Intenesence (I wouldn’t have expected it).
type Any .NET Type that the template knows about. You should use the .NET type name (as opposed to C# or VB.NET type).
In C# the parameters are created like this:
var arguments = new Dictionary();
arguments.Add("MyProperty", new PropertyData("String", typeof(string)));
To pass parameters from your code you need to create a Dictionary<string, PropertyData>, add your parameters and pass them as the second argument into the TemplateHost constructor (the first can be any string as far as I can tell).

Simple Sample

The Template

<#@ template language="C#" debug="True" #>
<#@ output extension="txt" #>
<#@ assembly name="System.dll" #>
<#@ import namespace="System" #>
<#@ property processor="PropertyProcessor" name="MyProperty" type="Nullable<Int32>"#>
<#@ property processor="PropertyProcessor" name="MyName" type="String"#>
My Property Test
<# if (MyProperty.HasValue) {#>
Property Value: <#= MyProperty.Value #>!
<#}#>
Name: <#= MyName #>

C# code

static void Main(string[] args)
{
    // Prepare template parameters
    var arguments = new Dictionary<string, PropertyData>();
    arguments.Add("MyProperty", new PropertyData(42, typeof(int?)));
    arguments.Add("MyName", new PropertyData("Jack Stephens", typeof(string)));

    // Initialize GAX template host
    // The Template Host is from GAX, not the default host
    var host = new TemplateHost("Random String", arguments);
    host.TemplateFile = Path.Combine(Directory.GetCurrentDirectory(), 
        "PropertyTest.tt");

    // Transform template
    string template = File.ReadAllText(host.TemplateFile);

    ITextTemplatingEngine engine = new Engine();
    string output = engine.ProcessTemplate(template, host);

    Console.Write(output);
    Console.ReadKey();
}

References

Monday, June 13, 2011

Portland Code Camp 2011 Presentation Notes

Again, I'm late getting this up. I will give usual excuses of being busy. In the future I will not promise anything before the next weekend after the code camp.

Since I developed this talk on this blog, this entry will essentially be a link list. I put a copy of the slides in Google doc and you can reference it here

This presentation is similar, but not the same as a presentation I gave at the Boise Code Camp in February. In the interest of being DRY (Don’t Repeat Yourself) I will reference the notes for that presentation.

Tools

For this presentation, I used the Tangible T4 Editory and the T4 Toolbox.

Template Parts

I presented a slide that showed the basic template parts in a small mock template:

<#@ template language="C#" #>
<#@ directive property=“value” #>
<# var item = "Statement Block"; #>
Text Block 
<#= "Expression Block" #>
<#+ 
    string ClassFeatureBlock(string thingy)
    {
        return thingy;
    } 
#>

Hello World Monty

I showed some of the elementary features of T4 templates by refactoring a basic template that would create a text file that contained the infamous words “Hello World”. A script of that exercise is here

Basic Code Generation Demonstration

To demonstrate Code Generation I set out to generate a simple T-SQL Select Statement using Sql Management Objects (SMO).

Here I will refer to the Boise Code Camp Notes.

Generating Multiple Files using T4 Toolbox

I used the result of the Basic Code Generation Demonstration to attempt to generate select scripts for all the tables in a given database. This demonstration was based on a series of blog posts by Oleg Synch (Part 1, Part 2, Part 3 & Part 4).

I do intend to give my take on this process. Perhaps that is why I'm over a week late on these notes. I will add a link to these notes later.

GAX Property Directive

I discussed using Guidance Automation Extensions's property directive to overcome T4's lack of native support for passing parameters into templates. This part was based on another Oleg Synch article Understanding T4: <#@ property #> directive.

Again, I will add links to future blogs post(s) on this subject here.

Generating a Nullable ADO.NET DataSet Wrapper

This is when I went to Show and Tell Mode. I demonstrate a Nullable DataSet Wrapper that I wrote in these blog entries. I wrote the templates in VB.NET to generate code in C#.

Part 1, Part 2, Part 3 & Part 4

Last Word

This presentation reached too far and, like Icarus, I failed to hit the mark. The number of forward links is a sign of that. I intend to back-blog in the areas the missing material and add links when I am done.

Tuesday, May 31, 2011

Writing Kindle Presentation Notes with MobiPocket Creator

Next weekend I will be presenting on Code Generation with T4 Templates at the Portland Code Camp and I bought a Kindle a week or so ago. So, how do I play with my new toy without getting behind on preparing for my presentation?

Mobipocket Creator Publisher Edition

I am creating small ebooks with Word and Mobipocket Creator Publisher Edition. I work though a demo or other presentation block and write it in Word. Then I use the Mobipocket Creator to create an ebook. I put it on my Kindle and review it before I go to bed.

Is this really a net gain or just a way to justify playing with my new toy instead of doing real work? I will find out come Saturday in Portland

Tuesday, May 17, 2011

Hanselminutes #266 and Alt.Net Seattle’s "Open Source in Business"

I just finished listening to Hanselminutes Open Source vs. Making Money vs. Freaking Lasers - Are we all Evil? With Chris Sells and it reminded me of the Open Source in Business session that I attended at Alt.Net Seattle. This post is attempting to tie these two things together.

Open Source vs. Commercial Software

Should we share our non-core software? Scott and Chris suggest that open sourcing your software is a cost. If you open source a project to increase good will among the programmer community; it is a good thing but not necessarily profitable.

In Alt.Net Seattle’s Open Source in Business, a couple of participants claim that their companies benefited from "free" programming and used the contributor’s list to fill positions.

Scott and Chris talk about the Portland open source culture and how making money isn’t necessarily the biggest thing in Portland. Some of the open source that way to keep more of what they make.

Companies Being Evil

Apple and Google have done evil things in the last few years, but Microsoft is still evil. Scott and Chris suggested that Microsoft isn’t well organized enough to be evil. No company of any size is beloved by everyone.

Is evil associated with making money over customers? In any publicly traded company, stock holder value is king over everything else. Microsoft may feel more evil because they charge us directly. People may like them better if pricing was less complicated (the pricing discussion goes on from there, but I won’t go there in this post).

Since Google and Facebook make money from advertising and don't charge us anything, they feel less evil (Facebook privacy policy makes them feel more evil to me).

Originality of .NET Open Source

At Alt.NET we also discussed the relative lack of originality in the .NET ecosystem. Many of the major open source projects (NHibernate, NUnit, etc.) are copies of Java open source projects. Perhaps many .NET developers are shy about starting ambitious open source project fearing that Microsoft will somehow co-opt it. Perhaps Microsoft is too disorganized to get out of the way of some cool open source project.

This may be the way that Microsoft is evil. It also could be that the companies that use Microsoft software are more conservative and value safety over innovation. I've worked for a few companies that view open source as evil -- to these companies, Microsoft is a crusader fighting against the chaos.

Sunday, May 08, 2011

Thoughts durring Alt .NET Seattle: Explaining my lame laptop.

Confession: I cam to Alt .Net Seattle with a HP Pavilion Entertainment PC Laptop with a HUGE screen. The thing is a monster. And it is totally uncool. I am not going to replace it for another year: I am not made of money.

I wonder if there are things I can to to acknowledge my folly in a light self deprecating way. Perhaps a sticker that says something like "I'm a slack jawed yokel from Spokane" or somehow making light of the fact that it isn't an Apple (it's 40% Apple here), but that seams too heavy to me. A sticker would be nice but what should is say? etc.