Freigeben über


Walkthrough: Creating and Running Text Templates

You can use the toolkit in Domain-Specific Language Tools to transform text templates. By transforming (also known as running) text templates, you can generate text artifacts that combine text blocks with information supplied from input sources, such as models. For more information, see Generating Artifacts Using Text Templates.

This walkthrough shows you how to use Domain-Specific Language Tools to create and transform a text template. You will use the Class Diagrams solution template as a starting point for a domain-specific language that you create.

Tasks illustrated in this walkthrough include:

  • Creating a domain-specific language

  • Creating a custom text template

  • Adding code to a text template

  • Transforming a text template

  • Generating classes based on a model

  • Adding class features to a text template

  • Generating code from relationships

  • Generating code from relationship properties

  • Splitting a text template into multiple files

  • Generating text from a class feature

  • Validating the model before code generation

  • Accessing multiple models from a text template

    Hinweis

    If errors occur in this walkthrough, see Common Validation Errors and Warnings in Text Templates.

Prerequisites

To complete this walkthrough, you will need:

Creating a Domain-Specific Language

First, you use the Domain-Specific Language Designer Wizard to create a domain-specific language called ClassDiagramExample. Then you open the experimental build.How to: Create Domain-Specific Language Solutions

To create a domain-specific language

  1. On the File menu, point to New, and click Project.

    The New Project dialog box appears.

  2. Under Project types, expand Other Project Types, and click Extensibility.

  3. Under Visual Studio installed templates, click Domain-Specific Language Designer.

  4. In Name, type ClassDiagramExample, and click OK.

  5. On the Select Domain-Specific Language Options page, click Class Diagrams in the list of solution templates, and then click Next.

  6. On the Define New Model File Type page, under What extension should model files use?, type testcd, and then click Next.

  7. On the Specify Product Details page, replace the name of the company with Fabrikam, and click Finish.

    The ClassDiagramExample project opens.

    Hinweis

    When you create a project, the system automatically generates the default templates. When you generate a template, you will see a message that warns you not to run text templates from untrusted sources. If you do not want this message to appear again, select the Do not show this message again check box, and click OK. Otherwise, click OK.

  8. On the Build menu, click Rebuild Solution.

  9. On the Debug menu, click Start Debugging.

    The experimental build opens.

    Hinweis

    You complete the rest of this walkthrough in the experimental build. For more information about the experimental build, see Experimental Build.

  10. In Solution Explorer, open Sample.testcd.

    This model contains the following classes:

    • Member

    • Library

    • Reservation

    • Loan

    • Title

    • Item

    This is not a complete list. You might use these classes to implement a system for reserving books at a library.

Creating a Custom Text Template

Now that the experimental build is running, you can create a custom text template. Later, you will use this text template to return information about the Sample.testcd model.

To create a text template

  1. On the Project menu, click Add New Item.

    The Add New Item dialog box appears.

  2. Under Visual Studio installed templates, click Text File.

  3. In Name, type LibraryCode.tt, and click Add.

    The system adds the file to the project.

    Hinweis

    When you name a text template, you can either specify any extension that you want, such as .tt, or you can leave the default extension of .txt.

  4. In Solution Explorer, click LibraryCode.tt.

    Warnung

    When you add LibraryCode.tt to the project, the file will be highlighted in Solution Explorer, but it is not selected. If you do not select LibraryCode.tt, the following step will not work.

  5. In the Properties window, set the Custom Tool property to TextTemplatingFileGenerator.

    Hinweis

    If you use .tt as the extension for a text template, the system automatically sets the Custom Tool property to TextTemplatingFileGenerator. You can use other extensions if you want. If you use another extension, you will have to set the Custom Tool property manually.

  6. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

    The system generates the file, LibraryCode.cs. To display this file, expand the LibraryCode.tt node.

    Hinweis

    The extension of the generated file is .cs by default. However, you can change the extension of the file that you just generated and the default extension for files that you generate later. For more information, see How to: Specify File Output Types in Text Templates.

Adding Code to a Text Template

With the blank text template open, you can add some directives, statements, and expressions. In text templates, you indicate directives with <#@ tags, statements with <# tags, and expressions with <#= tags. For more information, see Adding Code to Text Templates.

In this procedure, you add directives and statements that generate a list of the classes in the Sample.testcd model.

To add code to a text template

  1. Copy the following two directives to LibraryCode.tt:

    Hinweis

    By adding the two directives at the top, template and ClassDiagramExample, you can use the elements of the Sample.testcd model as classes in the text template code. For more information, see Accessing Models from Text Templates.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    
  2. Copy the following statement and expression lines to LibraryCode.tt. This code generates a list of the classes that are in the Sample.testcd model:

    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
    #>
        <#= type.Name#>
    <#
        }
    #>
    

Transforming a Text Template

With the text template complete, the next step is to transform LibraryCode.tt. This transformation generates an output file that contains a simple list of the classes in the Sample.testcd model.

To transform the text template

  1. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

    Hinweis

    You can transform all of the text templates in your solution by clicking Transform All Templates on the Solution Explorer toolbar. Also, you transform a single text template every time that you save the file.

  2. In Solution Explorer, double-click LibraryCode.cs.

    The file opens with the following output:

    Item

    Title

    Book

    Member

    Library

    Loan

    MultipleAssociation1

    Reservation

    MultipleAssociation2

    Hinweis

    At this point, you will see an error in the Error List window. You did not cause this error by running the custom tool. Because the generated text file has an extension of .cs, Visual Studio is trying to compile it. At this intermediate stage, the generated text will not compile. You can ignore this error.

  3. Delete the contents of LibraryCode.cs, and then repeat step 1.

    The system regenerates the file.

    Note   You can also delete the output file itself, not just the contents of the file. You regenerate the output file every time that you transform the text template.

Generating Classes Based on a Model

This next procedure modifies the text template to generate Visual C# classes in LibraryCode.cs, which is based on the Sample.testcd model.

To generate Visual C# classes in the output file

  1. Replace the code in LibraryCode.tt with the following code.

    The changes are highlighted.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
    #>
    <#        if(type is ModelClass)        {#>public class <#= type.Name#>{}<#        }#>
    <#
        }
    #>
    

    Text without text template tags (<# and #>) is a text block and will be generated in the output file exactly as you type it. In this case, the text block is public class and its corresponding opening and closing brackets. The expression statement <#= type.Name#> adds the class name to the output file LibraryCode.cs. For more information, see Adding Code to Text Templates.

    The output file reflects the format of the text template. The text public class <#= type.Name> and the opening and closing parentheses for the class appear on the left side of LibraryCode.tt. Because these items appear on the left side, the system formats the output file LibraryCode.cs with consistent indentations. This technique is used in various areas in the rest of this walkthrough.

  2. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

    Hinweis

    The compilation error from previous steps no longer appears.

  3. Open LibraryCode.cs.

    The system now generates the classes as Visual C# classes instead of as a simple list:

    public class Item
    {
    }
    public class Title
    {
    }
    public class Book
    {
    }
    public class Member
    {
    }
    public class Library
    {
    }
    public class Loan
    {
    }
    public class Reservation
    {
    }
    

Adding Class Features to a Text Template

Your C# code takes its class names, such as library, from the names in your model. Your text template will generate faulty code if you type a name into a model class that is not a valid C# identifier.

In the following procedure, you create a helper function that translates the name from the model into a valid C# identifier.

You create helper functions in text templates by adding them to class feature blocks. In text templates, you indicate class feature blocks with <#+ tags. For more information, see Class Feature Syntax.

You also call the Warning method, which you can use to add custom messages to the Error List window. The custom warning tells the user that the name of a model class contains no valid characters.

To add helper functions to the text template

  1. Replace the code in LibraryCode.tt with the following code.

    The changes are highlighted.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    <#@ import namespace = "System.Text.RegularExpressions" #>
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
            if(type is ModelClass)        {            ModelClass classType = (ModelClass)type;            string className = MakeValidName(type.Name);            if(string.IsNullOrEmpty(className))            {                // Generate a validation constraint                Warning (String.Format("ClassName '{0}' is not a valid class name", type.Name));            }            else            {#>public class <#= className#> <# if(classType.Superclass != null) { #>: <#= classType.Superclass.Name#> <# } #>{}<#            }         }    }#><#+private static string MakeValidName(string typeName){    //Use the System.Text.RegularExpressions namespace specified in the import directive    //Remove non-alpha characters    string fixedName = Regex.Replace(typeName,"[^a-zA-Z]","");    return fixedName;}
    #>
    
  2. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

  3. Open LibraryCode.cs.

    The output looks like this:

    public class Item 
    {
    }
    
    public class Title 
    {
    }
    
    public class Book : Item 
    {
    }
    
    public class Member 
    {
    }
    
    public class Library 
    {
    }
    
    public class Loan 
    {
    }
    
    public class Reservation 
    {
    }
    

Generating Code from Relationships

In the next procedure, you extend LibraryCode.tt to generate code based on the domain relationships in the model file Sample.testcd. In each ModelClass, you generate code for the ModelAttributes, which are linked through the ClassHasAttributes relationship. From the domain-specific language definition, you can see whether this relationship generates the Attributes property for the domain class, ModelClass.

To add private fields to the classes in the generated text output file

  1. Replace the code in LibraryCode.tt with the following code.

    The changes are highlighted.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    <#@ import namespace = "System.Text.RegularExpressions" #>
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
            if(type is ModelClass)
            {
                ModelClass classType = (ModelClass)type;
    
                string className = MakeValidName(type.Name);
                if (string.IsNullOrEmpty(className))
                {
                   // Generate a validation constraint
                   Warning(String.Format("ClassName '{0}' is not a valid class name", type.Name));
                }
                else
                {
    #>public class <#= className#> <# if(classType.Superclass != null) { #>: <#= classType.Superclass.Name#> <# } #>
    
    {
    <#            foreach(ModelAttribute attribute in classType.Attributes)            {#>    <#= MakeValidName(attribute.Type)#> <#= MakeValidName(attribute.Name)#>;<#            }#>
    }
    
    <#
                }
            }
        }
    #>
    
    <#+private static string MakeValidName(string typeName){    //Use the System.Text.RegularExpressions namespace specified in the import directive    //Remove non-alpha characters    string fixedName = Regex.Replace(typeName,"[^a-zA-Z]","");    return fixedName;}
    #>
    
  2. In Solution Explorer, right-click LibraryCode.tt, and click Run Custom Tool.

  3. Open LibraryCode.cs.

    The classes are now generated as Visual C# classes that have data types included in them. The output looks like this:

    public class Item 
    {
    }
    
    public class Title 
    {
        string name;
    }
    
    public class Book : Item 
    {
    }
    
    public class Member 
    {
    }
    
    public class Library 
    {
    }
    
    public class Loan 
    {
        Date commenced;
    }
    
    public class Reservation 
    {
        Date made;
       }
    

Generating Code from Relationship Properties

In this procedure, you add code to implement bidirectional associations by using a pair of properties. There is one property in the class at each end of the relationship.

To perform this task, you must obtain the names that the user has given to each end of the relationship. These properties are for the relationship itself, so you must navigate to individual instance links of the relationship by using its GetLinksTo… static methods.

To generate the bidirectional associations in the output file

  1. Replace the code in LibraryCode.tt with the following code.

    The changes are highlighted.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    <#@ import namespace = "System.Text.RegularExpressions" #>
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
            if(type is ModelClass)
            {
                ModelClass classType = (ModelClass)type;
    
                string className = MakeValidName(type.Name);
                if (string.IsNullOrEmpty(className))
                {
                   // Generate a validation constraint
                   Warning(String.Format("ClassName '{0}' is not a valid class name", type.Name));
                }
                else
                {
    #>
    public class <#= className#> <# if(classType.Superclass != null) { #>: <#= classType.Superclass.Name#> <# } #>
    
    {
    <#            foreach(ModelAttribute attribute in classType.Attributes)            {#>    <#= attribute.Type#> <#= attribute.Name#>;<#            }            foreach(BidirectionalAssociation association in BidirectionalAssociation.GetLinksToBidirectionalTargets(classType))            {                ModelClass associatedClass = association.BidirectionalTarget;                // Note that we use the Role name here.                if(!string.IsNullOrEmpty(association.SourceRoleName) && !string.IsNullOrEmpty(association.TargetRoleName))                {#>    private <#= associatedClass.Name#> <#= association.TargetRoleName#>Value;    public <#= associatedClass.Name#> <#= association.TargetRoleName#>    {        get{ return <#= association.TargetRoleName#>Value; }        set        {                      if (<#= association.TargetRoleName#> != value)           {if (<#= association.TargetRoleName#> != null) <#= association.TargetRoleName#>.<#=association.SourceRoleName#> = null;<#= association.TargetRoleName#>Value = value;if (value != null) {            <#= association.TargetRoleName#>Value.<#=association.SourceRoleName#>=this;}    }        }    }<#                }                else                {                    Warning(String.Format("Ignoring BidirectionalAssociation from {0} to {1} because its SourceRoleName or TargetRoleName is not defined", classType.Name, associatedClass.Name));                }            }#><#            foreach(BidirectionalAssociation association in BidirectionalAssociation.GetLinksToBidirectionalSources(classType))            {                ModelClass associatedClass = association.BidirectionalSource;                if(!string.IsNullOrEmpty(association.SourceRoleName) && !string.IsNullOrEmpty(association.TargetRoleName))                {#>    private <#= associatedClass.Name#> <#= association.SourceRoleName#>Value;    public <#= associatedClass.Name#> <#= association.SourceRoleName#>    {        get {return <#= association.SourceRoleName#>Value; }        set        {                        if (<#= association.SourceRoleName#> != value){if (<#= association.SourceRoleName#> != null)  <#= association.SourceRoleName#>.<#= association.TargetRoleName#> = null;<#= association.SourceRoleName#>Value = value;if (value != null){<#= association.SourceRoleName#>Value.<#= association.TargetRoleName#>=this;}     }               }    }<#                }                else                {                    Warning(String.Format("Ignoring BidirectionalAssociation from {0} to {1} because its SourceRoleName or TargetRoleName is not defined", classType.Name, associatedClass.Name));                }            }#>
    }
    
    <#
              }
            }
        }
    #>
    
    <#+private static string MakeValidName(string typeName){    //Use the System.Text.RegularExpressions namespace specified in the import directive    //Remove non-alpha characters    string fixedName = Regex.Replace(typeName,"[^a-zA-Z]","");    return fixedName;}
    #>
    
  2. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

  3. Open LibraryCode.cs.

    Bidirectional associations appear in the Reservation and Item classes as properties, as shown in the following example:

    public class Item 
    {
        private Title titleValue;
        public Title title
        {
            get {return titleValue; }
            set
            {
               if (title != value)
      {
          if (title != null) 
         title.stock = null;
    titleValue = value;
    if (value != null)
    {
        titleValue.stock=this;
    }
             }        
            }
        }
    }
    
    public class Title 
    {
        string name;
    
        private Item stockValue;
        public Item stock
        {
            get{ return stockValue; }
            set
            {
                if (stock != value)
                {
           if (stock != null) 
         stock.title = null;
     stockValue = value;
     if (value != null) 
     {
                     stockValue.title=this;
     }
             }
            }
        }
    }
    
    public class Book : Item 
    {
    }
    
    public class Member 
    {
    }
    
    public class Library 
    {
    }
    
    public class Loan 
    {
        Date commenced;
    }
    
    public class Reservation 
    {
        Date made;
    }
    

Splitting a Text Template into Multiple Files

If a text template becomes too large to manage effectively, you can split it into multiple files. This makes it easier to manage and it allows you to reuse common code. For more information, see How to: Split Text Templates Into Multiple Files.

Because your text template contains a helper function, you can separate it from the rest of the code by moving the helper function into a separate file. You can use the include directive in the original text template to access the helper function in the new file.

To split a text template into multiple files

  1. On the Project menu, click Add New Item.

    The Add New Item - Debugging dialog box appears.

  2. In the Visual Studio installed templates pane, click Text File.

  3. In Name, type HelperFunctions.ttinclude, and then click Add.

    The system adds file to your project.

  4. Copy the import directive and the helper functions from LibraryCode.tt into HelperFunctions.ttinclude.

    HelperFunctions.ttinclude now looks like this:

    <#@ import namespace = "System.Text.RegularExpressions" #>
    <#+
    private static string MakeValidName(string typeName)
    {
        //Use the System.Text.RegularExpressions namespace specified in the import directive
        //Remove non-alpha characters
        string fixedName = Regex.Replace(typeName,"[^a-zA-Z]","");        return fixedName;}
    #>
    
  5. On the File menu, click Save HelperFunctions.ttinclude.

  6. Delete the copied import directive and helper functions from LibraryCode.tt.

  7. Add the following directive to LibraryCode.tt:

    <#@ include file = "HelperFunctions.ttinclude"#>
    
  8. On the File menu, click Save LibraryCode.tt.

  9. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

  10. Open LibraryCode.cs.

    The output looks like this:

    public class Item 
    {
        private Title titleValue;
        public Title title
        {
            get {return titleValue; }
            set
            {
                if (title != value)
       {
           if (title != null) 
          title.stock = null;
           titleValue = value;
     if (value != null)
     {
         titleValue.stock=this;
     }
             }        
            }
        }
    }
    
    public class Title 
    {
        string name;
    
        private Item stockValue;
        public Item stock
        {
            get{ return stockValue; }
            set
            {
                          if (stock != value)
               {
    if (stock != null) 
    stock.title = null;
    stockValue = value;
    if (value != null) 
    {
                stockValue.title=this;
    }
        }
            }
        }
    }
    
    public class Book : Item 
    {
    }
    
    public class Member 
    {
    }
    
    public class Library 
    {
    }
    
    public class Loan 
    {
        Date commenced;
    }
    
    public class Reservation 
    {
        Date made;
    }
    

Generating Text from a Class Feature

You can generate text from a helper function in a class feature, whether it is in the main file or a separate included file. In this example, you generate code from the source and target ends of the BidirectionalAssociation. Then you move that code into a helper function and call it from the main template.

To generate text from a class feature

  1. Open HelperFunctions.ttinclude.

  2. Append this function after the existing function.

    Hinweis

    The function contains several blocks, but they are all class feature blocks (“<#+”). Also, MakeValidName has been applied to the role names.

    <#+
    private void CreateAccessor(ModelClass classType, ModelClass associatedClass, string fromRoleName, string toRoleName)
    {
                    if(!string.IsNullOrEmpty(toRoleName) && !string.IsNullOrEmpty(fromRoleName))
                    {
                       string validClassName = MakeValidName(associatedClass.Name);
                       string validFromName = MakeValidName(fromRoleName);
                       string validToName = MakeValidName(toRoleName);
    #>
    
        private <#= validClassName#> <#= validFromName#>Value;
        public <#= validClassName#> <#= validFromName#>
        {
            get{ return <#= validFromName #>Value; }
            set
            {
               if (<#= validFromName#> != value)
               {
    if (<#= validFromName#> != null) 
    <#= validFromName#>.<#=validToName#> = null;
    <#= validFromName#>Value = value;
    if (value != null) 
    {
                <#= validFromName#>Value.<#=validToName#>=this;
    }
       }
            }
        }
    <#+
                    }
                    else
                    {
                        Warning(String.Format("Ignoring BidirectionalAssociation from {0} to {1} because its SourceRoleName or TargetRoleName is not defined", classType.Name, associatedClass.Name));
                    }
    }
    #>
    
  3. On the File menu, click Save HelperFunctions.ttinclude.

  4. Replace the code in LibraryCode.tt with the following code.

    The changes are highlighted.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"#>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    <#@ include file = "HelperFunctions.ttinclude"#>
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
            if(type is ModelClass)
            {
                ModelClass classType = (ModelClass)type;
    
                string className = MakeValidName(type.Name);
                if (string.IsNullOrEmpty(className))
                {
                   // We should also generate a proper validation constraint for this
                   Warning(String.Format("ClassName '{0}' is not a valid class name",
                           type.Name));
                }
                else
                {
    
    #>
    public class <#= className#> <# if(classType.Superclass != null) { #>: <#= classType.Superclass.Name#> <# } #>
    
    {
    <#
                foreach(ModelAttribute attribute in classType.Attributes)
                {
    #>
        <#= attribute.Type#> <#= attribute.Name#>;
    <#
                }
                foreach(ClassOperation operation in classType.Operations) 
                {
    #>
        public void <#= operation.Name#>()
        {
        }
    <#
                }
    #>
    <#
                foreach(BidirectionalAssociation association in BidirectionalAssociation.GetLinksToBidirectionalTargets(classType))
                {                CreateAccessor(classType, association.BidirectionalTarget, association.TargetRoleName, association.SourceRoleName);            }
    #>
    <#
                foreach(BidirectionalAssociation association in BidirectionalAssociation.GetLinksToBidirectionalSources(classType))
                {CreateAccessor(classType, association.BidirectionalSource, association.SourceRoleName, association.TargetRoleName);            }
    #>
    }
    
    <#
              }
            }
        }
    #>
    
  5. In Solution Explorer, right-click LibraryCode.tt, and then click Run Custom Tool.

    The system saves your changes.

Validating the Model Before Code Generation

Certain characteristics of the model in Sample.testcd will cause your generator to generate incorrect code. These cases include:

  • Multiple ModelClasses that have the same name (or that have the same name after illegal characters and digits are removed).

  • Multiple ModelAttributes and Association roles with the same name in the same ModelClass.

  • Empty type name for a ModelAttribute.

  • Loops in the graph of inheritance relationships

As you develop your code generator, you will find other examples of incorrect code. To discourage the language user from creating models that have these errors, you should create appropriate validation constraints that will be applied when the user saves the model file.

In general, you should write validation constraints whenever you create templates or any other tools that process models. Using validation constraints ensures that the models that are passed to your tools and templates are clean enough for them to work from. You can display error messages when the language user validates the model or when a tool or template generates code from the model. However, you should display error messages as early as possible so that the language user can easily identify the elements to which the errors refer. For more information, see Walkthrough: Adding Validation to a Domain Model.

Accessing Multiple Models from a Text Template

You can access more than one model from the same text template. In this section, you create a second model, and then you use one text template for both of them. After you transform the text template, TestMultiple.tt, the code for both models will appear in the output file, TestMultiple.txt.

Hinweis

For more information about how to use multiple models with text templates, see Accessing Models from Text Templates.

To add a second model to your project

  1. On the Project menu, click Add New Item.

    The Add New Item dialog box appears.

  2. In the Add New Item dialog box, scroll down to the My Templates section, and click ClassDiagramExample.

    Warnung

    Do not click Class Diagram in the Visual Studio installed templates section.

  3. In Name, type Second.testcd, and click Add.

    The system adds the file to the project.

  4. In Solution Explorer, open Second.testcd.

  5. From the Toolbox, drag two class objects onto the model designer.

  6. On the File menu, click Save Second.testcd to save the new model.

To access multiple models from a text template

  1. On the Project menu, click Add New Item.

    The Add New Item dialog box appears.

  2. In the Visual Studio installed templates pane, click Text File.

  3. In Name, type TestMultiple.tt, and click Add.

    The system adds the file to the project.

  4. In Solution Explorer, click TestMultiple.tt.

  5. In the Properties window, be sure you set the Custom Tool property to TextTemplatingFileGenerator.

  6. Add the following directives to the top of the file.

    <#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" #>
    <#@ output extension=".txt" #>
    
  7. Add the following directives.

    These directives allow you to access the models.

    Hinweis

    The provides parameter for the Second.testcd model changes the name of the ModelRoot property to SecondModelRoot. This change prevents a conflict with the name of the ModelRoot property for the Sample.testcd model.

    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Sample.testcd'" #>
    <#@ ClassDiagramExample processor="ClassDiagramExampleDirectiveProcessor" requires="fileName='Second.testcd'" provides="ModelRoot=SecondModelRoot"#>
    
  8. Add the following code, which generates a list of the classes that are in each of the two models.

    Model 1:
    <#
        foreach(ModelType type in this.ModelRoot.Types)
        {
    #>
            <#= type.Name#>
    <#
        }
    #>
    
    Model 2:
    <#
        foreach(ModelType type in this.SecondModelRoot.Types)
        {
    #>
            <#= type.Name#>
    <#
        }
    #> 
    
  9. In Solution Explorer, right-click TestMultiple.tt, and then click Run Custom Tool.

  10. In Solution Explorer, open TestMultiple.txt, which looks like the following:

    Model 1:
            Library
            Member
            Reservation
            Book
            Item
            CD
            Title
            MultipleAssociation 1
            Loan Relation
    
    Model 2:
            ModelClass 1
            ModelClass 2
    

Security

For more information, see Security of Text Templates.

Next Steps

This walkthrough does not provide a complete description of all functionality for text templates. For example, you can debug text templates, create custom directive processors, specify culture, and include assemblies in text templates. For more information, see Generating Artifacts Using Text Templates.

See Also

Concepts

Generating Artifacts Using Text Templates

Architecture of the Text Template Transformation Process

Using Built-in Directives in Text Templates

Adding Code to Text Templates

Domain-Specific Language Tools Glossary