Understanding T4: <#@ property #> directive
The property directive was introduced by Microsoft in 2006 as part of Guidance Automation Extensions. It was designed for passing parameter values from a Visual Studio template to a T4 template. It is implemented as a custom directive in a special T4 host shipped with GAX. Here is how GAT help file defines the property directive:
… so called “property processor” declarations … define template properties use to pass parameters to the template.
Very limited information is available about this directive. Information in this article is based on reverse engineering of GAX template host and GAT documentation.
Syntax
<#@ property processor=“PropertyProcessor” name=“…” type=“…” converter=“…” editor=“…” #>
processor
The processor parameter specifies name of the custom processor T4 engine will use to process this directive. This parameter is required and must be set to “PropertyProcessor”.
name
The name parameter specifies name of the property that will be generated in the compiled TextTransformation. This parameter is required and must contain a valid C#/Visual Basic property name.
type
The type parameter specifies a type for the property to be generated. This parameter is optional and will default to System.String. When specified, this parameter needs to provide a valid type name. Language-specific type names are not supported. For example, instead of “int” you need to specify “System.Int32″. Namespace of the type name can be omitted if the template contains an import directive with this namespace. Types from custom assemblies can be used if the template contains a corresponding assembly directive.
converter
The converter parameter specifies a type descending from TypeConverter. It appears to be designed for converting property value from a string value stored in Visual Studio template to an actual value that will be passed to the template. This parameter is optional. As the example below illustrates, this parameter is an equivalent of specifying TypeConverterAttribute for a property declaration.
editor
The editor parameter specifies a type descending from UITypeEditor. We can speculate that it was intended as a mechanism to specify the editor GAX would use in the new item wizard when collecting property values from the user. However, it appears that implementation of this parameter in GAX host is invalid and was abandoned in favor of specifying the editor type in XML definition of the wizard itself. This parameter is optional. As the example below illustrates, this parameter is an equivalent of specifying EditorAttribute for a property declaration.
Under the hood
Template in the example below uses the property directive to define a property of type Color. This type is defined in System.Drawing.dll assembly, which this template references using an assembly directive. The template takes advantage of an import directive and specifies the type parameter as simply Color instead of System.Drawing.Color.
Template
<#@ template language=“C#” debug=“True” #> <#@ output extension=“txt” #> <#@ assembly name=“System.dll” #> <#@ assembly name=“System.Drawing.dll” #> <#@ assembly name=“System.Drawing.Design.dll” #> <#@ import namespace=“System” #> <#@ import namespace=“System.Drawing” #> <#@ import namespace=“System.Drawing.Design” #> <#@ property processor=“PropertyProcessor” name=“MyProperty” type=“Color” converter=“ColorConverter” editor=“ColorEditor), typeof(UITypeEditor” #> Property Value: <#= MyProperty #>
Note that editor parameter uses a workaround to force GAX PropertyProcessor to generate a valid EditorAttribute declaration, which requires two parameters, while PropertyProcessor and editor parameter were implemented to support only one.
As the example below illustrates, GAX PropertyProcessor generates a public property that returns value stored in the Arguments dictionary of the current template host.
Template Compiled by GAX Host
using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using Microsoft.VisualStudio.TextTemplating; using Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates; namespace Microsoft.VisualStudio.TextTemplatingd5b789b3e4504916b775e26a974dceb5 { public class GeneratedTextTransformation: TextTransformation { public override string TransformText() { this.Write(“Property Value: “); this.Write(ToStringHelper.ToStringWithCulture(MyProperty)); return this.GenerationEnvironment.ToString(); } [TypeConverter(typeof(ColorConverter))] [Editor(typeof(ColorEditor), typeof(UITypeEditor))] [TemplateProperty] public Color MyProperty { get { return (Color)TemplateHost.CurrentHost.Arguments[“MyProperty”].Value; } } } }
Note that converter parameter of the directive generated a TypeConverterAttribute and editor parameter generated EditorAttribute for the property.
Here is an example of code that creates GAX template host and runs the T4 template, passing Color.AntiqueWhite as the property value.
Code Running Template in GAX Host
using System; using System.Collections.Generic; using System.Drawing; using System.IO; using Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates; using Microsoft.VisualStudio.TextTemplating; namespace PropertyDirectivePot { class Program { static void Main(string[] args) { // Prepare template parameters var arguments = new Dictionary<string, PropertyData>(); arguments.Add(“MyProperty”, new PropertyData(Color.AntiqueWhite, typeof(Color))); // Initialize GAX template host string currentDirectory = Directory.GetCurrentDirectory(); TemplateHost host = new TemplateHost(currentDirectory, arguments); host.TemplateFile = Path.Combine(currentDirectory, “PropertyTest.tt”); // Transform template string template = File.ReadAllText(host.TemplateFile); ITextTemplatingEngine engine = new Engine(); string output = engine.ProcessTemplate(template, host); // Save output string outputFile = Path.ChangeExtension(host.TemplateFile, “.txt”); File.WriteAllText(outputFile, output); } } }
Output
Property Value: Color [AntiqueWhite]
Alternative Directive Processor
T4 Editor by Clarius Consulting relies on the property processor in its “Preview Transformation” functionality. It installs its own implementation of the property directive processor, which appears to be derived from the GAX implementation. It supports the same parameters as the GAX property processor, including an equally dysfunctional implementation of the editor parameter.
T4 Editor registers the Clarius property processor in HKLM\SOFTWARE\Microsoft\VisualStudio\X.0\TextTemplating\DirectiveProcessors registry key, making it available to all T4 templates running under the standard Visual Studio T4 host. In other words, with T4 Editor installed, you can use the property directive without having to use or even install GAX.
Clarius property processor uses a different mechanism for passing property values to the template. As the example below demonstrates, instead of relying on the custom template host, Clarius property processor uses the built-in CallContext.
Template Compiled by DSL Host
using System; using System.CodeDom.Compiler; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Runtime.Remoting.Messaging; using Microsoft.VisualStudio.TextTemplating; using Microsoft.VisualStudio.TextTemplating.VSHost; namespace Microsoft.VisualStudio.TextTemplatingE1DC528A375CF2A8146E176953CE1A46 { public class GeneratedTextTransformation : TextTransformation { public override string TransformText() { this.Write(“Property Value: “); this.Write(ToStringHelper.ToStringWithCulture(MyProperty)); return this.GenerationEnvironment.ToString(); } [TypeConverter(typeof(ColorConverter))] [Editor(typeof(ColorEditor), typeof(UITypeEditor))] [GeneratedCode(“Text Template Transformation Wrapper”, “1.0.61214.0″)] public Color MyProperty { get { return (Color)CallContext.LogicalGetData(“MyProperty”); } } } }
Another minor difference that may not be worth mentioning is that the Clarius property processor generates a standard GeneratedCodeAttribute instead of the custom TemplatePropertyAttribute used by GAX.
In order to pass property value to a template using the Clarius property processor, you need to call CallContext.LogicalSetData method as demonstrated in the Example4.tt and ProcessTemplate.tt of my previous article - How to generate multiple outputs from single T4 template. Ultimately, it produces the exact same output file as running this template under GAX template host.
Final Thoughts
You will be using the property directive when developing T4 templates for guidance automation packages. Outside of GAX, this directive has a very limited use because it produces read-only properties and requires either a custom host or a third-party directive processor.
Although it would be easy to create your own property directive processor, it is questionable whether the cost of developing and deploying it to every developer’s workstation justifies its benefits. Read-write properties are very easy to define in class feature blocks; use of CallContext is very straightforward.
References
- Testing T4 templates using the GAX host by Jose Escrich
Download
About T4
T4 (Text Template Transformation Toolkit) is a template-based code generation engine. It is available in Visual Studio 2008 and as a download in DSL and GAT toolkits for Visual Studio 2005. T4 engine allows you to use ASP.NET-like template syntax to generate C#, T-SQL, XML or any other text files.
Ready for more? Read about <#@ xsd #> directive or go back to the overview for more information and examples.



I was getting an EntryPointNotFoundException on the line:
string output = engine.ProcessTemplate(template, host);
I had to dig out Microsoft.VisualStudio.TextTemplating.dll version 8.1.0.0 to get that line to work.