Compartilhar via


Usando o Visual Studio ModelBus em um modelo de texto

Se você escrever modelos de texto que leem um modelo que contém referências do Visual Studio ModelBus, será conveniente resolver as referências para acessar os modelos de destino. Nesse caso, você precisa adaptar os modelos de texto e as DSLs (linguagens específicas de domínio) referenciadas:

  • A DSL que é o destino das referências precisa ter um Adaptador ModelBus configurado para acesso a partir de modelos de texto. Se você também acessar a DSL de outro código, o adaptador reconfigurado será necessário, juntamente com o adaptador padrão do ModelBus.

    O gerenciador do adaptador precisa herdar de VsTextTemplatingModelingAdapterManager e precisa ter o atributo [HostSpecific(HostName)].

  • O modelo precisa herdar de ModelBusEnabledTextTransformation.

Observação

Se você quiser ler modelos DSL que não contêm referências do ModelBus, poderá usar os processadores de diretiva gerados em seus projetos DSL. Para obter mais informações, confira Acessando modelos de modelos de texto.

Para obter mais informações sobre modelos de texto, confira Geração de código em tempo de design usando modelos de texto T4.

Criar um adaptador de barramento de modelo para acesso por meio de modelos de texto

Para resolver uma referência do ModelBus em um modelo de texto, a DSL de destino precisa ter um adaptador compatível. Os modelos de texto são executados em um AppDomain separado dos editores de documentos do Visual Studio e, portanto, o adaptador precisa carregar o modelo em vez de acessá-lo por meio do DTE.

  1. Se a solução DSL de destino não tiver um projeto ModelBusAdapter, crie um usando o assistente de Extensão do Modelbus:

    1. Baixe e instale a Extensão do Visual Studio ModelBus, caso ainda não tenha feito isso. Para obter mais informações, confira SDK de visualização e modelagem.

    2. Abra o arquivo de definição de DSL. Clique com o botão direito do mouse na superfície de design e clique em Habilitar Modelbus.

    3. Na caixa de diálogo, selecione Desejo expor essa DSL ao ModelBus. É possível selecionar as duas opções se você deseja que essa DSL exponha os próprios modelos e consuma referências a outras DSLs.

    4. Clique em OK. Um novo projeto "ModelBusAdapter" é adicionado à solução de DSL.

    5. Clique em Transformar Todos os Modelos.

    6. Recriar a solução.

  2. Se você quiser acessar a DSL de um modelo de texto e de outro código, como o comando, duplique o projeto ModelBusAdapter:

    1. No Windows Explorer, copie e cole a pasta que contém ModelBusAdapter.csproj.

    2. Renomeie o arquivo de projeto (por exemplo, para T4ModelBusAdapter.csproj).

    3. No Gerenciador de Soluções, clique com o botão direito do mouse na solução, aponte para Adicionar e clique em Novo Projeto. Localize o novo projeto do adaptador, T4ModelBusAdapter.csproj.

    4. Em cada arquivo *.tt do novo projeto, altere o namespace.

    5. Clique com o botão direito do mouse no novo projeto no Gerenciador de Soluções e clique em Propriedades. No editor de propriedades, altere os nomes do assembly gerado e do namespace padrão.

    6. No projeto DslPackage, adicione uma referência ao novo projeto do adaptador para que ele tenha referências a ambos os adaptadores.

    7. Em DslPackage\source.extension.tt, adicione uma linha que referencie seu novo projeto de adaptador.

      <MefComponent>|T4ModelBusAdapter|</MefComponent>
      
    8. Clique em Transformar Todos os Modelos e recompile a solução. Nenhum erro de build deve ocorrer.

  3. No novo projeto de adaptador, adicione referências aos seguintes assemblies:

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

    • Altere a declaração de AdapterManagerBase para que ela herde de VsTextTemplatingModelingAdapterManager.

      public partial class <#= dslName =>AdapterManagerBase :

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

    • Próximo ao final do arquivo, substitua o atributo HostSpecific antes da classe AdapterManager. Remova a seguinte linha:

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

      Insira a seguinte linha:

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

      Esse atributo filtra o conjunto de adaptadores que está disponível quando um consumidor de modelbus procura um adaptador.

  5. Clique em Transformar Todos os Modelos e recompile a solução. Nenhum erro de build deve ocorrer.

Escrever um modelo de texto que possa resolver referências do ModelBus

Normalmente, você começa com um modelo que lê e gera arquivos de uma DSL de "origem". Esse modelo usa a diretiva gerada no projeto DSL de origem para ler arquivos de modelo de origem da maneira descrita em Acessando modelos de modelos de texto. No entanto, a DSL de origem contém referências de ModelBus a uma DSL de "destino". Portanto, você deseja habilitar o código de modelo para resolver as referências e acessar a DSL de destino. Portanto, você precisa adaptar o modelo seguindo estas etapas:

  • Altere a classe base do modelo para ModelBusEnabledTextTransformation.

  • Inclua hostspecific="true" na diretiva de modelo.

  • Adicione referências de assembly à DSL de destino e ao adaptador e habilite o ModelBus.

  • Você não precisa da diretiva gerada como parte da 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.
#>

Quando esse modelo de texto é executado, a diretiva SourceDsl carrega o arquivo Sample.source. O modelo pode acessar os elementos desse modelo, começando por this.ModelRoot. O código pode usar as classes de domínio e as propriedades dessa DSL.

Além disso, o modelo pode resolver referências do ModelBus. Quando as referências apontam para o modelo de destino, as diretivas de assembly permitem que o código use as classes de domínio e as propriedades da DSL desse modelo.

  • Se você não usar uma diretiva gerada por um projeto DSL, também deverá incluir o mostrado a seguir.

    <#@ assembly name = "Microsoft.VisualStudio.Modeling.Sdk.11.0" #>
    <#@ assembly name = "Microsoft.VisualStudio.TextTemplating.Modeling.11.0" #>
    
  • Use this.ModelBus para obter acesso ao ModelBus.

Passo a passo: testando um modelo de texto que usa o ModelBus

Neste passo a passo, você seguirá estas etapas:

  1. Construa duas DSLs. Uma DSL, o Consumidor, tem uma propriedade ModelBusReference que pode se referir à outra DSL, o Provedor.

  2. Crie dois adaptadores do ModelBus no Provedor: um para acesso por modelos de texto, outro para código comum.

  3. Crie modelos de instância das DSLs em apenas um projeto experimental.

  4. Defina uma propriedade de domínio em um modelo para apontar para o outro modelo.

  5. Escreva um manipulador de clique duplo que abre o modelo que é apontado.

  6. Escreva um modelo de texto que possa carregar o primeiro modelo, seguir a referência ao outro modelo e ler o outro modelo.

Construir uma DSL acessível para o ModelBus

  1. Crie uma solução DSL. Para este exemplo, selecione o modelo de solução Fluxo de Tarefas. Defina o nome da linguagem de programação como MBProvider e a extensão de nome de arquivo como ".provide".

  2. No diagrama Definição de DSL, clique com o botão direito do mouse em uma parte em branco do diagrama que não esteja perto da parte superior e clique em Habilitar Modelbus.

    Se você não vir Habilitar o Modelbus, baixe e instale a extensão VMSDK do ModelBus.

  3. Na caixa de diálogo Habilitar Modelbus, selecione Expor essa DSL ao ModelBus e clique em OK.

    Um novo projeto ModelBusAdapter é incluído na solução.

Agora você tem uma DSL que pode ser acessada por modelos de texto por meio do ModelBus. As referências a ele podem ser resolvidas no código de comandos, manipuladores de eventos ou regras, todos os quais operam no AppDomain do editor de arquivos de modelo. No entanto, os modelos de texto são executados em um AppDomain separado e não podem acessar um modelo quando ele está sendo editado. Se você quiser acessar referências do ModelBus a essa DSL de um modelo de texto, precisará ter um ModelBusAdapter separado.

Criar um adaptador do ModelBus configurado para modelos de texto

  1. No Explorador de Arquivos, copie e cole a pasta que contém ModelBusAdapter.csproj.

    Nomeie a pasta T4ModelBusAdapter.

    Renomeie o arquivo de projeto T4ModelBusAdapter.csproj.

  2. Em Gerenciador de Soluções, adicione T4ModelBusAdapter à solução MBProvider. Clique com o botão direito do mouse na solução, aponte para Adicionar e escolha Projeto Existente.

  3. Clique com o botão direito do mouse no nó do projeto T4ModelBusAdapter e clique em Propriedades. Na janela de propriedades do projeto, altere o Nome do Assembly e o Namespace Padrão para Company.MBProvider.T4ModelBusAdapters.

  4. Em cada arquivo *.tt em T4ModelBusAdapter, insira "T4" na última parte do namespace, de modo que a linha se pareça com a mostrada a seguir.

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

  5. No projeto DslPackage, adicione uma referência do projeto ao assembly T4ModelBusAdapter.

  6. Em DslPackage\source.extension.tt, adicione a linha a seguir em <Content>.

    <MefComponent>|T4ModelBusAdapter|</MefComponent>

  7. No projeto T4ModelBusAdapter, adicione uma referência a: Microsoft.VisualStudio.TextTemplating.Modeling.11.0

  8. Abra T4ModelBusAdapter\AdapterManager.tt:

    1. Altere a classe base de AdapterManagerBase para VsTextTemplatingModelingAdapterManager. Essa parte do arquivo agora é semelhante à mostrada a seguir.

      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. Próximo ao final do arquivo, insira o atributo adicional a seguir antes da classe AdapterManager.

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

      O resultado é semelhante ao mostrado a seguir.

      /// <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. Clique em Transformar Todos os Modelos na barra de título do Gerenciador de Soluções.

  10. Pressione F5.

  11. Verifique se a DSL está funcionando. No projeto experimental, abra Sample.provider. Feche a Instância Experimental do Visual Studio.

    Referências de ModelBus a essa DSL agora podem ser resolvidas em modelos de texto e também em código comum.

Construir uma DSL com uma propriedade de domínio de referência do ModelBus

  1. Crie uma DSL usando o modelo de solução Linguagem Mínima. Nomeie a linguagem MBConsumer e defina a extensão de nome de arquivo como ".consume".

  2. No projeto DSL, adicione uma referência ao assembly DSL MBProvider. Clique com o botão direito do mouse em MBConsumer\Dsl\References e clique em Adicionar Referência. Na guia Procurar, localize MBProvider\Dsl\bin\Debug\Company.MBProvider.Dsl.dll

    Isso permite que você crie um código que usa a outra DSL. Se você quiser criar referências a várias DSLs, adicione-as também.

  3. No diagrama Definição de DSL, clique com o botão direito na parte principal do diagrama e clique em Habilitar ModelBus. Na caixa de diálogo, selecione Habilitar essa DSL para Consumir o ModelBus.

  4. Na classe ExampleElement, adicione uma nova propriedade de domínio MBR e, no janela Propriedades, defina o tipo dela como ModelBusReference.

  5. Clique com o botão direito do mouse na propriedade de domínio e clique em Editar propriedades específicas do ModelBusReference. Na caixa de diálogo, selecione um elemento de modelo.

    Defina o filtro de caixa de diálogo do arquivo para o mostrado a seguir.

    Provider File|*.provide

    A substring após "|" é um filtro para a caixa de diálogo de seleção de arquivo. Você pode defini-lo para permitir arquivos usando *.*

    Na lista Tipo de elemento de modelo, insira os nomes de uma ou mais classes de domínio na DSL do provedor (por exemplo, Company.MBProvider.Task). Elas podem ser classes abstratas. Se você deixar a lista em branco, o usuário poderá definir a referência para qualquer elemento.

  6. Feche a caixa de diálogo e Transformar Todos os Modelos.

    Você criou uma DSL que pode conter referências a elementos em outra DSL.

Criar uma referência de ModelBus para outro arquivo na solução

  1. Na solução MBConsumer, pressione CTRL+F5. Uma instância experimental do Visual Studio é aberta no projeto MBConsumer\Debugging.

  2. Adicione uma cópia de Sample.provide ao projeto MBConsumer\Debugging. Isso é necessário porque uma referência de ModelBus precisa se referir a um arquivo na mesma solução.

    1. Clique com o botão direito do mouse na solução, aponte para Adicionar e escolha Item Existente.

    2. Na caixa de diálogo Adicionar Item, defina o filtro como Todos os Arquivos (*.*).

    3. Navegue até MBProvider\Debugging\Sample.provide e clique em Adicionar.

  3. Abra o Sample.consume.

  4. Clique em uma forma de exemplo e, na janela Propriedades, clique em [...] na propriedade MBR. Na caixa de diálogo, clique em Procurar e selecione Sample.provide. Na janela elementos, expanda o tipo Tarefa e selecione um dos elementos.

  5. Salve o arquivo. (Ainda não feche a instância experimental do Visual Studio.)

    Você criou um modelo que contém uma referência de ModelBus a um elemento em outro modelo.

Resolver uma referência de ModelBus em um modelo de texto

  1. Na instância experimental do Visual Studio, abra um arquivo de modelo de texto de exemplo. Defina seu conteúdo como mostrado a seguir.

    <#@ 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 #>
    <#
          }
      }
    #>
    
    

    Lembre-se também dos seguintes pontos:

    • Os atributos hostSpecific e inherits da diretiva template precisam ser definidos.

    • O modelo de consumidor é acessado da maneira usual por meio do processador de diretiva que foi gerado nessa DSL.

    • As diretivas de assembly e importação precisam ser capazes de acessar o ModelBus e os tipos da DSL do provedor.

    • Se você souber que muitos MBRs estão vinculados ao mesmo modelo, é melhor chamar CreateAdapter apenas uma vez.

  2. Salve o modelo. Verifique se o arquivo de texto resultante é semelhante ao mostrado a seguir.

    ExampleElement1
    ExampleElement2
         ExampleElement2 is linked to Task: Task2
    

Resolver uma referência de ModelBus em um manipulador de gestos

  1. Feche a instância experimental do Visual Studio, se ela estiver em execução.

  2. Adicione um arquivo chamado MBConsumer\Dsl\Custom.cs e defina o conteúdo dele como o seguinte:

    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. Pressione Ctrl+F5.

  4. Na instância experimental do Visual Studio, abra Debugging\Sample.consume.

  5. Clique duas vezes em uma forma.

    Se você tiver definido o MBR nesse elemento, o modelo referenciado será aberto e o elemento referenciado será selecionado.

Observação

O componente Transformação de Modelo de Texto é instalado automaticamente como parte da carga de trabalho de Desenvolvimento de extensões do Visual Studio. Você também pode instalá-lo na guia Componentes individuais do Instalador do Visual Studio, na categoria SDKs, bibliotecas e estruturas. Instale o componente SDK de Modelagem na guia Componentes individuais.