Usar ModelBus de Visual Studio en plantillas de texto

Si escribe plantillas de texto que leen un modelo que contiene referencias de Visual Studio ModelBus, es posible que le interese resolver las referencias para acceder a los modelos de destino. En ese caso, tiene que adaptar las plantillas de texto y los lenguajes específicos de dominio (DSL) a los que se hace referencia:

  • El DSL que es el destino de las referencias debe tener un adaptador de ModelBus configurado para el acceso desde plantillas de texto. Si también accede al DSL desde otro código, se requiere el adaptador reconfigurado además del adaptador de ModelBus estándar.

    El administrador de adaptadores debe heredar de VsTextTemplatingModelingAdapterManager y debe tener el atributo [HostSpecific(HostName)].

  • La plantilla debe heredar de ModelBusEnabledTextTransformation.

Nota

Si quiere leer modelos de DSL que no contienen referencias de ModelBus, puede usar los procesadores de directivas que se generan en los proyectos de DSL. Para obtener más información, consulte Acceso a modelos desde plantillas de texto.

Para obtener más información sobre las plantillas de texto, consulte Generación de código en tiempo de diseño mediante plantillas de texto T4.

Creación de un adaptador de ModelBus para el acceso desde plantillas de texto

Para resolver una referencia de ModelBus en una plantilla de texto, el DSL de destino debe tener un adaptador compatible. Las plantillas de texto se ejecutan en un AppDomain independiente de los editores de documentos de Visual Studio y, por tanto, el adaptador debe cargar el modelo, en lugar de acceder a él a través de DTE.

  1. Si la solución de DSL de destino no tiene un proyecto ModelBusAdapter, cree uno mediante el Asistente para extensiones de ModelBus:

    1. Descargue e instale la extensión de Visual Studio ModelBus, si aún no lo ha hecho. Para obtener más información, consulte SDK de visualización y modelado.

    2. Abra el archivo de definición de DSL. Haga clic con el botón derecho en la superficie de diseño y, después, haga clic en Enable ModelBus (Habilitar ModelBus).

    3. En el cuadro de diálogo, seleccione I want to expose this DSL to the ModelBus (Quiero exponer este DSL a ModelBus). Puede seleccionar ambas opciones si quiere que este DSL exponga sus modelos y use referencias a otros DSL.

    4. Haga clic en OK. Se agrega un nuevo proyecto "ModelBusAdapter" a la solución de DSL.

    5. Haga clic en Transformar todas las plantillas.

    6. Recompilar la solución.

  2. Si quiere acceder al DSL desde una plantilla de texto y desde otro código, como un comando, duplique el proyecto ModelBusAdapter:

    1. En el Explorador de Windows, copie y pegue la carpeta que contiene ModelBusAdapter.csproj.

    2. Cambie el nombre del archivo del proyecto (por ejemplo, a T4ModelBusAdapter.csproj).

    3. En el Explorador de soluciones, haga clic con el botón derecho en el nodo de solución, elija Agregar y, después, haga clic en Proyecto existente. Busque el nuevo proyecto de adaptador (T4ModelBusAdapter.csproj).

    4. En cada archivo *.tt del nuevo proyecto, cambie el espacio de nombres.

    5. Haga clic con el botón derecho en el nuevo proyecto en el Explorador de soluciones y, después, haga clic en Propiedades. En el editor de propiedades, cambie los nombres del ensamblado generado y del espacio de nombres predeterminado.

    6. En el proyecto DslPackage, agregue una referencia al nuevo proyecto de adaptador para que tenga referencias a ambos adaptadores.

    7. En DslPackage\source.extension.tt, agregue una línea que haga referencia al nuevo proyecto de adaptador.

      <MefComponent>|T4ModelBusAdapter|</MefComponent>
      
    8. Transforme todas las plantillas y recompile la solución. No deberían producirse errores de compilación.

  3. En el nuevo proyecto de adaptador, agregue referencias a los ensamblados siguientes:

    • Microsoft.VisualStudio.TextTemplating.11.0
    • Microsoft.VisualStudio.TextTemplating.Modeling.11.0
  4. En AdapterManager.tt:

    • Cambie la declaración de AdapterManagerBase para que herede de VsTextTemplatingModelingAdapterManager.

      public partial class <#= dslName =>AdapterManagerBase :

      Microsoft.VisualStudio.TextTemplating.Modeling.VsTextTemplatingModelingAdapterManager { ...

    • Casi al final del archivo, reemplace el atributo HostSpecific antes de la clase AdapterManager. Quite la línea siguiente:

      [DslIntegration::HostSpecific(DslIntegrationShell::VsModelingAdapterManager.HostName)]

      Inserte la línea siguiente:

      [Microsoft.VisualStudio.Modeling.Integration.HostSpecific(HostName)]

      Este atributo filtra el conjunto de adaptadores que está disponible cuando un consumidor de ModelBus busca un adaptador.

  5. Transforme todas las plantillas y recompile la solución. No deberían producirse errores de compilación.

Cómo escribir una plantilla de texto que pueda resolver referencias de ModelBus

Normalmente, se empieza a trabajar con una plantilla que lee y genera archivos a partir de un DSL "de origen". Esta plantilla usa la directiva que se genera en el proyecto de DSL de origen para leer los archivos del modelo de origen de la manera que se describe en Acceso a modelos desde plantillas de texto. Pero el DSL de origen contiene referencias de ModelBus a un DSL "de destino". Así pues, le interesa habilitar el código de plantilla para resolver las referencias y acceder al DSL de destino. Por lo tanto, debe adaptar la plantilla con estos pasos:

  • Cambie la clase base de la plantilla a ModelBusEnabledTextTransformation.

  • Incluya hostspecific="true" en la directiva de plantilla.

  • Agregue referencias de ensamblado al DSL de destino y su adaptador, y para habilitar ModelBus.

  • No necesita la directiva que se genera como parte del DSL de destino.

<#@ template debug="true" hostspecific="true" language="C#"
inherits="Microsoft.VisualStudio.TextTemplating.Modeling.ModelBusEnabledTextTransformation" #>
<#@ SourceDsl processor="SourceDslDirectiveProcessor" requires="fileName='Sample.source'" #>
<#@ output extension=".txt" #>
<#@ assembly name = "Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0" #>
<#@ assembly name = "Company.TargetDsl.Dsl.dll" #>
<#@ assembly name = "Company.TargetDsl.T4ModelBusAdapter.dll" #>
<#@ assembly name = "System.Core" #>
<#@ import namespace="Microsoft.VisualStudio.Modeling.Integration" #>
<#@ import namespace="Company.TargetDsl" #>
<#@ import namespace="Company.TargetDsl.T4ModelBusAdapters" #>
<#@ import namespace="System.Linq" #>
<#
  SourceModelRoot source = this.ModelRoot; // Usual access to source model.
  // In the source DSL Definition, the root element has a model reference:
  using (TargetAdapter adapter = this.ModelBus.CreateAdapter(source.ModelReference) as TargetAdapter)
  {if (adapter != null)
   {
      // Get the root of the target model:
      TargetRoot target = adapter.ModelRoot;
    // The source DSL Definition has a class "SourceElement" embedded under the root.
    // (Let's assume they're all in the same model file):
    foreach (SourceElement sourceElement in source.Elements)
    {
      // In the source DSL Definition, each SourceElement has an MBR property:
      ModelBusReference elementReference = sourceElement.ReferenceToTarget;
      // Resolve the target model element:
      TargetElement element = adapter.ResolveElementReference<TargetElement>(elementReference);
#>
     The source <#= sourceElement.Name #> is linked to: <#= element.Name #> in target model: <#= target.Name #>.
<#
    }
  }}
  // Other useful code: this.Host.ResolvePath(filename) gets an absolute filename
  // from a path that is relative to the text template.
#>

Cuando se ejecuta esta plantilla de texto, la directiva SourceDsl carga el archivo Sample.source. La plantilla puede acceder a los elementos de ese modelo, empezando por this.ModelRoot. El código puede usar las clases de dominio y las propiedades de ese DSL.

Además, la plantilla puede resolver referencias de ModelBus. Cuando las referencias apuntan al modelo de destino, las directivas de ensamblado permiten que el código use las clases de dominio y las propiedades del DSL de ese modelo.

  • Si no usa una directiva generada por un proyecto de DSL, debe incluir también lo siguiente.

    <#@ assembly name = "Microsoft.VisualStudio.Modeling.Sdk.11.0" #>
    <#@ assembly name = "Microsoft.VisualStudio.TextTemplating.Modeling.11.0" #>
    
  • Use this.ModelBus para obtener acceso a ModelBus.

Tutorial: Prueba de una plantilla de texto que usa ModelBus

En este tutorial realizará los pasos siguientes:

  1. Construya dos DSL. Un DSL (Consumer) tiene una propiedad ModelBusReference que puede hacer referencia al otro DSL (Provider).

  2. Cree dos adaptadores de ModelBus en Provider: uno para el acceso mediante plantillas de texto y otro para el código normal.

  3. Cree modelos de instancia de los DSL en un único proyecto experimental.

  4. Establezca una propiedad de dominio en un modelo para que apunte al otro modelo.

  5. Escriba un controlador de doble clic que abra el modelo al que se apunta.

  6. Escriba una plantilla de texto que pueda cargar el primer modelo, siga la referencia al otro modelo y léalo.

Construcción de un DSL que sea accesible para ModelBus

  1. Cree una solución de DSL. Para este ejemplo, seleccione la plantilla de solución Flujo de tareas. Establezca el nombre del lenguaje en MBProvider y la extensión del nombre de archivo en ".provide".

  2. En el diagrama de definición de DSL, haga clic con el botón derecho en una parte en blanco del diagrama que no esté cerca de la parte superior y, luego, haga clic en Enable ModelBus (Habilitar ModelBus).

    Si no ve Enable ModelBus (Habilitar ModelBus), descargue e instale la extensión VMSDK ModelBus.

  3. En el cuadro de diálogo Enable ModelBus (Habilitar ModelBus), seleccione Expose this DSL to the ModelBus (Exponer este DSL a ModelBus) y haga clic en Aceptar.

    Se agrega un nuevo proyecto (ModelBusAdapter) a la solución.

Ahora tiene un DSL al que pueden acceder las plantillas de texto a través de ModelBus. Las referencias a él se pueden resolver en el código de comandos, controladores de eventos o reglas, todos los cuales funcionan en el AppDomain del editor de archivos de modelo. En cambio, las plantillas de texto se ejecutan en un AppDomain independiente y no pueden acceder a un modelo cuando se está editando. Si quiere acceder a las referencias de ModelBus a este DSL desde una plantilla de texto, debe tener un ModelBusAdapter independiente.

Creación de un adaptador de ModelBus configurado para plantillas de texto

  1. En el Explorador de archivos, copie y pegue la carpeta que contiene ModelBusAdapter.csproj.

    Asigne a la carpeta el nombre T4ModelBusAdapter.

    Cambie el nombre del archivo de proyecto a T4ModelBusAdapter.csproj.

  2. En el Explorador de soluciones, agregue T4ModelBusAdapter a la solución MBProvider. Haga clic con el botón derecho en el nodo de la solución, seleccione Agregar y haga clic en Proyecto existente.

  3. Haga clic con el botón derecho en el nodo del proyecto T4ModelBusAdapter y, después, haga clic en Propiedades. En la ventana de propiedades del proyecto, cambie el nombre del ensamblado y el espacio de nombres predeterminado a Company.MBProvider.T4ModelBusAdapters.

  4. En cada archivo *.tt de T4ModelBusAdapter, inserte "T4" en la última parte del espacio de nombres, de modo que la línea sea similar a la siguiente.

    namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>.T4ModelBusAdapters

  5. En el proyecto DslPackage, agregue una referencia de proyecto a T4ModelBusAdapter.

  6. En DslPackage\source.extension.tt, agregue la línea siguiente bajo <Content>.

    <MefComponent>|T4ModelBusAdapter|</MefComponent>

  7. En el proyecto T4ModelBusAdapter, agregue una referencia a Microsoft.VisualStudio.TextTemplating.Modeling.11.0.

  8. Abra T4ModelBusAdapter\AdapterManager.tt:

    1. Cambie la clase base de AdapterManagerBase a VsTextTemplatingModelingAdapterManager. Ahora, esta parte del archivo es similar a lo que se muestra a continuación.

      namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>.T4ModelBusAdapters
      {
          /// <summary>
          /// Adapter manager base class (double derived pattern) for the <#= dslName #> Designer
          /// </summary>
          public partial class <#= dslName #>AdapterManagerBase
          : Microsoft.VisualStudio.TextTemplating.Modeling.VsTextTemplatingModelingAdapterManager
          {
      
    2. Casi al final del archivo, inserte el siguiente atributo adicional delante de la clase AdapterManager.

      [Microsoft.VisualStudio.Modeling.Integration.HostSpecific(HostName)]

      El resultado es similar al siguiente.

      /// <summary>
      /// ModelBus modeling adapter manager for a <#= dslName #>Adapter model adapter
      /// </summary>
      [Mef::Export(typeof(DslIntegration::ModelBusAdapterManager))]
      [Mef::ExportMetadata(DslIntegration::CompositionAttributes.AdapterIdKey,<#= dslName #>Adapter.AdapterId)]
      [DslIntegration::HostSpecific(DslIntegrationShell::VsModelingAdapterManager.HostName)]
      [Microsoft.VisualStudio.Modeling.Integration.HostSpecific(HostName)]
      public partial class <#= dslName #>AdapterManager : <#= dslName #>AdapterManagerBase
      {
      }
      
  9. Haga clic en Transformar todas las plantillas en la barra de título del Explorador de soluciones.

  10. Presione F5.

  11. Compruebe que el DSL funciona. En el proyecto experimental, abra Sample.provider. Cierre la instancia experimental de Visual Studio.

    Las referencias de ModelBus a este DSL ahora se pueden resolver en plantillas de texto y también en código normal.

Construcción de un DSL con una propiedad de dominio de referencia de ModelBus

  1. Cree un DSL mediante la plantilla de solución Lenguaje mínimo. Asigne al lenguaje el nombre MBConsumer y establezca la extensión de nombre de archivo en ".consume".

  2. En el proyecto de DSL, agregue una referencia al ensamblado de DSL MBProvider. Haga clic con el botón derecho en MBConsumer\Dsl\References y en Agregar referencia. En la pestaña Examinar, busque MBProvider\Dsl\bin\Debug\Company.MBProvider.Dsl.dll.

    Esto le permite crear código que use el otro DSL. Si quiere crear referencias a varios DSL, agréguelas también.

  3. En el diagrama de definición de DSL, haga clic con el botón derecho en el diagrama y, después, haga clic en Enable ModelBus (Habilitar ModelBus). En el cuadro de diálogo, seleccione Enable this DSL to Consume the ModelBus (Habilitar este DSL para consumir ModelBus).

  4. En la clase ExampleElement, agregue una nueva propiedad de dominio MBR y, en el ventana Propiedades, establezca su tipo en ModelBusReference.

  5. Haga clic con el botón derecho en la propiedad de dominio del diagrama y, después, haga clic en Edit ModelBusReference specific properties (Editar las propiedades específicas de ModelBusReference). En el cuadro de diálogo, seleccione un elemento de modelo.

    Establezca el filtro de cuadro de diálogo de archivo en lo siguiente.

    Provider File|*.provide

    La subcadena que aparece después de "|" es un filtro para el cuadro de diálogo de selección de archivos. Puede establecerlo para permitir cualquier archivo mediante *.*

    En la lista Model Element type (Tipo de elemento de modelo), escriba los nombres de una o varias clases de dominio en el DSL del proveedor (por ejemplo, Company.MBProvider.Task). Pueden ser clases abstractas. Si deja la lista en blanco, el usuario puede establecer la referencia a cualquier elemento.

  6. Cierre el cuadro de diálogo y transforme todas las plantillas.

    Ha creado un DSL que puede contener referencias a elementos de otro DSL.

Creación de una referencia de ModelBus a otro archivo de la solución

  1. En la solución MBConsumer, presione CTRL+F5. Se abre una instancia experimental de Visual Studio en el proyecto MBConsumer\Debugging.

  2. Agregue una copia de Sample.provide al proyecto MBConsumer\Debugging. Esto es necesario porque una referencia de ModelBus debe hacer referencia a un archivo de la misma solución.

    1. Haga clic con el botón derecho en el proyecto, seleccione Agregar y haga clic en Elemento existente.

    2. En el cuadro de diálogo Agregar elemento, establezca el filtro en Todos los archivos (*.*).

    3. Vaya a MBProvider\Debugging\Sample.provide y haga clic en Agregar.

  3. Abra Sample.consume.

  4. Haga clic en una forma de ejemplo y, en la ventana Propiedades, haga clic en […] en la propiedad MBR. En el cuadro de diálogo, haga clic en Examinar y seleccione Sample.provide. En la ventana de elementos, expanda el tipo Tarea y seleccione uno de los elementos.

  5. Guarde el archivo. (No cierre todavía la instancia experimental de Visual Studio).

    Ha creado un modelo que contiene una referencia de ModelBus a un elemento de otro modelo.

Resolución de una referencia de ModelBus en una plantilla de texto

  1. En la instancia experimental de Visual Studio, abra un archivo de plantilla de texto de ejemplo. Establezca su contenido de la manera que se indica a continuación.

    <#@ template debug="true" hostspecific="true" language="C#"
    inherits="Microsoft.VisualStudio.TextTemplating.Modeling.ModelBusEnabledTextTransformation" #>
    <#@ MBConsumer processor="MBConsumerDirectiveProcessor" requires="fileName='Sample.consume'" #>
    <#@ output extension=".txt" #>
    <#@ assembly name = "Microsoft.VisualStudio.Modeling.Sdk.Integration.11.0" #>
    <#@ assembly name = "Company.MBProvider.Dsl.dll" #>
    <#@ import namespace="Microsoft.VisualStudio.Modeling.Integration" #>
    <#@ import namespace="Company.MBProvider" #>
    <#
      // Property provided by the Consumer directive processor:
      ExampleModel consumerModel = this.ExampleModel;
      // Iterate through Consumer model, listing the elements:
      foreach (ExampleElement element in consumerModel.Elements)
      {
    #>
       <#= element.Name #>
    <#
        if (element.MBR != null)
      using (ModelBusAdapter adapter = this.ModelBus.CreateAdapter(element.MBR))
      {
              // If we allowed multiple types or DSLs in the MBR, discover type here.
        Task task = adapter.ResolveElementReference<Task>(element.MBR);
    #>
            <#= element.Name #> is linked to Task: <#= task==null ? "(null)" : task.Name #>
    <#
          }
      }
    #>
    
    

    Tenga en cuenta los puntos siguientes:

    • Los atributos hostSpecific y inherits de la directiva template deben estar establecidos.

    • Para acceder al modelo de consumidor, se sigue la manera habitual mediante el procesador de directivas que se generó en ese DSL.

    • Las directivas de ensamblado e importación deben poder acceder a ModelBus y a los tipos del DSL del proveedor.

    • Si sabe que muchas propiedades MBR están vinculadas al mismo modelo, es mejor llamar a CreateAdapter solo una vez.

  2. Guarde la plantilla. Compruebe que el archivo de texto resultante es similar al siguiente.

    ExampleElement1
    ExampleElement2
         ExampleElement2 is linked to Task: Task2
    

Resolución de una referencia de ModelBus en un controlador de gestos

  1. Cierre la instancia experimental de Visual Studio si se está ejecutando.

  2. Agregue un archivo denominado MBConsumer\Dsl\Custom.cs y establezca su contenido en lo siguiente:

    namespace Company.MB2Consume
    {
      using Microsoft.VisualStudio.Modeling.Integration;
      using Company.MB3Provider;
    
      public partial class ExampleShape
      {
        public override void OnDoubleClick(Microsoft.VisualStudio.Modeling.Diagrams.DiagramPointEventArgs e)
        {
          base.OnDoubleClick(e);
          ExampleElement element = this.ModelElement as ExampleElement;
          if (element.MBR != null)
          {
            IModelBus modelbus = this.Store.GetService(typeof(SModelBus)) as IModelBus;
            using (ModelBusAdapter adapter = modelbus.CreateAdapter(element.MBR))
            {
              Task task = adapter.ResolveElementReference<Task>(element.MBR);
              // Open a window on this model:
              ModelBusView view = adapter.GetDefaultView();
              view.Show();
              view.SetSelection(element.MBR);
            }
          }
        }
      }
    }
    
  3. Presione CTRL+F5.

  4. En la instancia experimental de Visual Studio, abra Debugging\Sample.consume.

  5. Haga doble clic en una forma.

    Si ha establecido la propiedad MBR en ese elemento, se abre el modelo al que se hace referencia y se selecciona el elemento al que se hace referencia.

Nota

El componente Transformación de plantilla de texto se instala de forma automática como parte de la carga de trabajo Desarrollo de extensiones de Visual Studio. También lo puede instalar desde la pestaña Componentes individuales del Instalador de Visual Studio, en la categoría SDK, bibliotecas y marcos. Instale el componente SDK de modelado desde la pestaña Componentes individuales.