Accès aux modèles depuis des modèles de texteAccessing Models from Text Templates

À l’aide de modèles de texte, vous pouvez créer des fichiers de rapports, les fichiers de code source et les autres fichiers de texte qui sont basées sur des modèles de langage spécifique à un domaine.By using text templates, you can create report files, source code files, and other text files that are based on domain-specific language models. Pour plus d’informations de base sur les modèles de texte, consultez génération de Code et les modèles de texte T4.For basic information about text templates, see Code Generation and T4 Text Templates. Les modèles de texte fonctionnent en mode expérimental lorsque vous déboguez votre DSL et fonctionnent également sur un ordinateur sur lequel vous avez déployé la DSL.The text templates will work in the experimental mode when you are debugging your DSL, and will also work on a computer on which you have deployed the DSL.

Note

Lorsque vous créez une solution DSL, l’exemple de modèle de texte *.tt fichiers sont générés dans le projet de débogage.When you create a DSL solution, sample text template *.tt files are generated in the debugging project. Lorsque vous modifiez les noms des classes de domaine, ces modèles ne fonctionnera plus.When you change the names of the domain classes, these templates will no longer work. Néanmoins, ils incluent les directives de base dont vous avez besoin et fournissent des exemples que vous pouvez mettre à jour pour correspondre à votre DSL.Nevertheless, they include the basic directives that you need, and provide examples that you can update to match your DSL.

Pour accéder à un modèle à partir d’un modèle de texte :To access a model from a text template:

  • Définir la propriété d’héritage de la directive de modèle ModelingTextTransformation.Set the inherit property of the template directive to ModelingTextTransformation. Cela permet d’accéder au magasin.This provides access to the Store.

  • Spécifiez les processeurs de directive pour la DSL que vous souhaitez accéder.Specify directive processors for the DSL that you want to access. Cela charge les assemblys de votre DSL afin que vous puissiez utiliser ses classes de domaine, les propriétés et les relations dans le code de votre modèle de texte.This loads the assemblies for your DSL so that you can use its domain classes, properties, and relationships in the code of your text template. Il charge également le fichier de modèle que vous spécifiez.It also loads the model file that you specify.

    A .tt fichier similaire à l’exemple suivant est créé dans le projet de débogage lorsque vous créez un nouveau Visual StudioVisual Studio solution à partir du modèle de langage minimale DSL.A .tt file similar to the following example is created in the Debugging project when you create a new Visual StudioVisual Studio solution from the DSL Minimal Language template.

<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" #>
<#@ output extension=".txt" #>
<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1'" #>

This text will be output directly.

This is the name of the model: <#= this.ModelRoot.Name #>

Here is a list of elements in the model:
<#
  // When you change the DSL Definition, some of the code below may not work.
  foreach (ExampleElement element in this.ExampleModel.Elements)
  {#>
<#= element.Name #>
<#
  }
#>

Notez les points suivants concernant ce modèle :Notice the following points about this template:

  • Le modèle peut utiliser les classes de domaine, les propriétés et les relations que vous avez définie dans la définition DSL.The template can use the domain classes, properties, and relationships that you defined in the DSL Definition.

  • Le modèle de charge le fichier de modèle que vous spécifiez dans le requires propriété.The template loads the model file that you specify in the requires property.

  • Une propriété dans this contient l’élément racine.A property in this contains the root element. À partir de là, votre code peut accéder à d’autres éléments du modèle.From there, your code can navigate to other elements of the model. Le nom de la propriété est généralement identique à la classe de domaine racine de votre DSL.The name of the property is usually the same as the root domain class of your DSL. Dans cet exemple, il s’agit de this.ExampleModel.In this example, it is this.ExampleModel.

  • Bien que le langage dans lequel sont écrits les fragments de code c#, vous pouvez générer le texte de tout type.Although the language in which the code fragments are written is C#, you can generate text of any kind. Vous pouvez également écrire du code Visual BasicVisual Basic en ajoutant la propriété language="VB" à le template la directive.You can alternatively write the code in Visual BasicVisual Basic by adding the property language="VB" to the template directive.

  • Pour déboguer le modèle, ajoutez debug="true" à le template la directive.To debug the template, add debug="true" to the template directive. Le modèle s’ouvre dans une autre instance de Visual StudioVisual Studio si une exception se produit.The template will open in another instance of Visual StudioVisual Studio if an exception occurs. Si vous souhaitez arrêter dans le débogueur à un moment spécifique dans le code, insérez l’instruction System.Diagnostics.Debugger.Break();If you want to break into the debugger at a specific point in the code, insert the statement System.Diagnostics.Debugger.Break();

    Pour plus d’informations, consultez débogage d’un modèle de texte T4.For more information, see Debugging a T4 Text Template.

Sur le processeur de directive DSLAbout the DSL directive processor

Le modèle peut utiliser les classes de domaine que vous avez définie dans la définition de votre DSL.The template can use the domain classes that you defined in your DSL Definition. Cela est généré par une directive qui apparaît généralement au début du modèle.This is brought about by a directive that usually appears near the start of the template. Dans l’exemple précédent, il est la suivante.In the previous example, it is the following.

<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1'" #>

Le nom de la directive ( MyLanguage, dans cet exemple) est dérivé du nom de votre DSL.The name of the directive ( MyLanguage, in this example) is derived from the name of your DSL. Il appelle une processeur de directive qui est générée dans le cadre de votre DSL.It invokes a directive processor that is generated as part of your DSL. Vous pouvez trouver le code source dans Dsl\GeneratedCode\DirectiveProcessor.cs.You can find its source code in Dsl\GeneratedCode\DirectiveProcessor.cs.

Le processeur de directive DSL effectue deux tâches principales :The DSL directive processor performs two principal tasks:

  • Il insère efficacement des directives d’assembly et d’importation dans le modèle qui fait référence à votre DSL.It effectively inserts assembly and import directives into the template that references your DSL. Cela vous permet d’utiliser des classes de votre domaine dans le code du modèle.This lets you use your domain classes in the template code.

  • Il charge le fichier que vous spécifiez dans le requires paramètre et définit une propriété this qui fait référence à l’élément racine du modèle chargé.It loads the file that you specify in the requires parameter, and sets a property in this that refers to the root element of the loaded model.

Avant d’exécuter le modèle de validation du modèleValidating the model before running the template

Vous pouvez provoquer le modèle à valider avant que le modèle est exécuté.You can cause the model to be validated before the template is executed.

<#@ MyLanguage processor="MyLanguageDirectiveProcessor" requires="fileName='Sample.myDsl1';validation='open|load|save|menu'" #>

Notez que :Notice that:

  1. Le filename et validation paramètres sont séparés par « ; » et il ne doit y avoir aucun autre séparateurs ou des espaces.The filename and validation parameters are separated with ";" and there must be no other separators or spaces.

  2. La liste des catégories de validation détermine les méthodes de validation sont exécutées.The list of validation categories determines which validation methods will be executed. Plusieurs catégories doivent être séparés par «|» et il ne doit y avoir aucun autre séparateurs ou des espaces.Multiple categories should be separated with "|" and there must be no other separators or spaces.

    Si une erreur est détectée, elle sera signalée dans la fenêtre d’erreurs, et le fichier de résultats contiendra un message d’erreur.If an error is found, it will be reported in the errors window, and the result file will contain an error message.

L’accès à plusieurs modèles à partir d’un modèle de texteAccessing multiple models from a text template

Note

Cette méthode vous permet de lire plusieurs modèles dans le même modèle, mais ne prend pas en charge les références ModelBus.This method lets you read multiple models in the same template but does not support ModelBus references. Pour lire des modèles qui sont reliées par leurs références de ModelBus, consultez à l’aide de Visual Studio ModelBus dans un modèle de texte.To read models that are interlinked by ModelBus References, see Using Visual Studio ModelBus in a Text Template.

Si vous souhaitez accéder à plus d’un modèle à partir du même modèle de texte, vous devez appeler le processeur de directive généré une fois pour chaque modèle.If you want to access more than one model from the same text template, you must call the generated directive processor one time for each model. Vous devez spécifier le nom de fichier de chaque modèle dans le requires paramètre.You must specify the file name of each model in the requires parameter. Vous devez spécifier les noms que vous souhaitez utiliser pour la classe de domaine racine dans le provides paramètre.You must specify the names that you want to use for the root domain class in the provides parameter. Vous devez spécifier des valeurs différentes pour le provides paramètres dans chacun des appels de directive.You must specify different values for the provides parameters in each of the directive calls. Par exemple, supposons que vous disposez de trois fichiers de modèle appelés Library.xyz, School.xyz et Work.xyz.For example, assume that you have three model files called Library.xyz, School.xyz, and Work.xyz. Pour y accéder à partir du même modèle de texte, vous devez écrire trois appels de directive qui ressemblent à celles ci-dessous.To access them from the same text template, you must write three directive calls that resemble the following ones.

<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='Library.xyz'" provides="ExampleModel=LibraryModel" #>
<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='School.xyz'" provides="ExampleModel=SchoolModel" #>
<#@ ExampleModel processor="<YourLanguageName>DirectiveProcessor" requires="fileName='Work.xyz'" provides="ExampleModel=WorkModel" #>

Note

Cet exemple de code est d’une langue qui est basée sur le modèle de solution de langage minimale.This example code is for a language that is based on the Minimal Language solution template.

Pour accéder aux modèles dans votre modèle de texte, vous pouvez maintenant écrire du code semblable au code dans l’exemple suivant.To access the models in your text template, you can now write code similar to the code in the following example.

<#
foreach (ExampleElement element in this.LibraryModel.Elements)
...
foreach (ExampleElement element in this.SchoolModel.Elements)
...
foreach (ExampleElement element in this.WorkModel.Elements)
...
#>
<#
For Each element As ExampleElement In Me.LibraryModel.Elements
...
For Each element As ExampleElement In Me.SchoolModel.Elements
...
For Each element As ExampleElement In Me.WorkModel.Elements
...
#>

Chargement des modèles de manière dynamiqueLoading models dynamically

Si vous souhaitez déterminer, lors de l’exécution, les modèles de charge, vous pouvez charger dynamiquement un fichier de modèle dans votre code de programme, au lieu d’utiliser la directive DSL spécifiques.If you want to determine at runtime which models to load, you can load a model file dynamically in your program code, instead of using the DSL-specific directive.

Toutefois, l’une des fonctions de la directive DSL spécifique est pour importer l’espace de noms DSL, afin que le code du modèle peut utiliser les classes de domaine définies dans ce DSL.However, one of the functions of the DSL-specific directive is to import the DSL namespace, so that the template code can use the domain classes defined in that DSL. Étant donné que vous n’utilisez pas la directive, vous devez ajouter <assembly > et <Importer > directives pour tous les modèles que vous pouvez charger.Because you are not using the directive, you must add <assembly> and <import> directives for all the models that you might load. C’est facile si les différents modèles que vous pouvez charger sont toutes les instances de la même DSL.This is easy if the different models that you might load are all instances of the same DSL.

Pour charger le fichier, la méthode la plus efficace est à l’aide de Visual StudioVisual Studio ModelBus.To load the file, the most effective method is by using Visual StudioVisual Studio ModelBus. Dans ce scénario, votre modèle de texte utilise une directive DSL spécifiques pour charger le premier modèle de manière habituelle.In a typical scenario, your text template will use a DSL-specific directive to load the first model in the usual way. Ce modèle contient des références de ModelBus à un autre modèle.That model would contain ModelBus References to another model. Vous pouvez utiliser ModelBus pour ouvrir le modèle référencé et accéder à un élément particulier.You can use ModelBus to open the referenced model and access a particular element. Pour plus d’informations, consultez à l’aide de Visual Studio ModelBus dans un modèle de texte.For more information, see Using Visual Studio ModelBus in a Text Template.

Dans un scénario habituel inférieur, vous souhaiterez ouvrir un fichier de modèle pour lequel vous avez uniquement un nom de fichier, et qui ne peut pas être en cours Visual StudioVisual Studio projet.In a less usual scenario, you might want to open a model file for which you have only a filename, and which might not be in the current Visual StudioVisual Studio project. Dans ce cas, vous pouvez ouvrir le fichier à l’aide de la technique décrite dans Comment : ouvrir un modèle à partir du fichier de Code de programme.In this case, you can open the file by using the technique described in How to: Open a Model from File in Program Code.

Génération de plusieurs fichiers à partir d’un modèleGenerating multiple files from a template

Si vous souhaitez générer plusieurs fichiers - par exemple, pour générer un fichier distinct pour chaque élément dans un modèle, il existe plusieurs approches possibles.If you want to generate a several files - for example, to generate a separate file for each element in a model, there are several possible approaches. Par défaut, un seul fichier est généré à partir de chaque fichier de modèle.By default, only one file is produced from each template file.

Fractionnement d’un fichier longSplitting a long file

Dans cette méthode, vous utilisez un modèle pour générer un seul fichier, séparé par un délimiteur.In this method, you use a template to generate a single file, separated by a delimiter. Puis vous fractionnez le fichier en parties.Then you split the file into its parts. Il existe deux modèles, un pour générer le fichier unique et l’autre à fractionner.There are two templates, one to generate the single file, and the other to split it.

LoopTemplate.t4 génère le fichier unique long.LoopTemplate.t4 generates the long single file. Notez que son extension de fichier est « .t4 », car il ne doit pas traité directement lorsque vous cliquez sur transformer tous les modèles.Notice that its file extension is ".t4", because it should not be processed directly when you click Transform All Templates. Ce modèle prend un paramètre qui spécifie la chaîne de délimiteur qui sépare les segments :This template takes a parameter, which specifies the delimiter string that separates the segments:

<#@ template ninherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" #>
<#@ parameter name="delimiter" type="System.String" #>
<#@ output extension=".txt" #>
<#@ MyDSL processor="MyDSLDirectiveProcessor" requires="fileName='SampleModel.mydsl1';validation='open|load|save|menu'" #>
<#
  // Create a file segment for each element:
  foreach (ExampleElement element in this.ExampleModel.Elements)
  {
    // First item is the delimiter:
#>
<#= string.Format(delimiter, element.Id) #>

   Element: <#= element.Name #>
<#
   // Here you generate more content derived from the element.
  }
#>

LoopSplitter.tt appelle LoopTemplate.t4et puis fractionne le fichier résultant en segments.LoopSplitter.tt invokes LoopTemplate.t4, and then splits the resulting file into its segments. Notez que ce modèle n’a pas à être un modèle de modélisation, car elle ne lit pas le modèle.Notice that this template does not have to be a modeling template, because it does not read the model.

<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="System.Runtime.Remoting.Messaging" #>
<#@ import namespace="System.IO" #>

<#
  // Get the local path:
  string itemTemplatePath = this.Host.ResolvePath("LoopTemplate.t4");
  string dir = Path.GetDirectoryName(itemTemplatePath);

  // Get the template for generating each file:
  string loopTemplate = File.ReadAllText(itemTemplatePath);

  Engine engine = new Engine();

  // Pass parameter to new template:
  string delimiterGuid = Guid.NewGuid().ToString();
  string delimiter = "::::" + delimiterGuid + ":::";
  CallContext.LogicalSetData("delimiter", delimiter + "{0}:::");
  string joinedFiles = engine.ProcessTemplate(loopTemplate, this.Host);

  string [] separateFiles = joinedFiles.Split(new string [] {delimiter}, StringSplitOptions.None);

  foreach (string nameAndFile in separateFiles)
  {
     if (string.IsNullOrWhiteSpace(nameAndFile)) continue;
     string[] parts = nameAndFile.Split(new string[]{":::"}, 2, StringSplitOptions.None);
     if (parts.Length < 2) continue;
#>
 Generate: [<#= dir #>] [<#= parts[0] #>]
<#
     // Generate a file from this item:
     File.WriteAllText(Path.Combine(dir, parts[0] + ".txt"), parts[1]);
  }
#>