Compartilhar via


Estender seu DSL usando MEF

Você pode exntend sua linguagem específica de domínio (DSL), usando o Managed Extensibility Framework (MEF).Você ou outros desenvolvedores poderão escrever extensões para o DSL sem alterar a definição de DSL e o código de programa.Essas extensões incluem comandos de menu, manipuladores de arrastar-e-soltar e validação.Os usuários poderão instalar seu DSL e, opcionalmente, instalar extensões para ele.

Além disso, quando você habilita o MEF no seu DSL, pode ser mais fácil para você gravar alguns dos recursos do seu DSL, mesmo se eles são criados em conjunto com a DSL.

Para obter mais informações sobre o MEF, consulte Managed Extensibility Framework (MEF).

Para ativar seu DSL ser estendido por MEF

  1. Crie uma nova pasta chamada MefExtension dentro do DslPackage project.Adicione os seguintes arquivos a ele:

    File name

    Conteúdo do arquivo

    CommandExtensionVSCT.tt

    Observação importanteImportante
    O GUID do conjunto neste arquivo para ser o mesmo que CommandSetId o GUID que é definido em DslPackage\GeneratedCode\Constants.tt
    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#
    // CmdSet Guid must be defined before master template is included
    // This Guid must be kept synchronized with the CommandSetId Guid in Constants.tt
    Guid guidCmdSet = new Guid ("00000000-0000-0000-0000-000000000000");
    string menuidCommandsExtensionBaseId="0x4000";
    #>
    <#@ include file="DslPackage\CommandExtensionVSCT.tt" #>

    CommandExtensionRegistrar.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\CommandExtensionRegistrar.tt" #>

    ValidationExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\ValidationExtensionEnablement.tt" #>

    ValidationExtensionRegistrar.tt

    Se você adicionar esse arquivo, você deve habilitar validação seu DSL usando pelo menos um dos switches da Editor\Validation no Explorer DSL.

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\ValidationExtensionRegistrar.tt" #>

    PackageExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\PackageExtensionEnablement.tt" #>
  2. Crie uma nova pasta chamada MefExtension dentro do Dsl project.Adicione os seguintes arquivos a ele:

    File name

    Conteúdo

    DesignerExtensionMetaDataAttribute.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\DesignerExtensionMetadataAttribute.tt" #>

    GestureExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\GestureExtensionEnablement.tt" #>

    GestureExtensionController.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="Dsl\GestureExtensionController.tt" #>
  3. Adicione a seguinte linha ao arquivo existente chamado DslPackage\Commands.vsct:

    <Include href="MefExtension\CommandExtensionVSCT.vsct"/>
    

    Inserir a linha após o existente <Include> diretiva.

  4. Abra DslDefinition.dsl.

  5. No Explorer DSL, selecione Editor\Validation.

  6. Na janela Properties, certifique-se de que pelo menos uma das propriedades nomeadas usa... is true.

  7. Na barra de ferramentas do Solution Explorer, clique em Transformar todos os modelos de.

    Os arquivos da subsidiária aparecem embaixo de cada um dos arquivos que você adicionou.

  8. Compile e execute a solução para verificar se ele ainda está funcionando.

Agora, seu DSL está habilitado para MEF.Você pode escrever os comandos de menu, manipuladores de gestos e restrições de validação como extensões MEF.Você pode escrever essas extensões em sua solução DSL junto com outros códigos personalizados.Além disso, você ou outros desenvolvedores podem gravar separada Visual Studio as extensões que estendem seu DSL.

Criando uma extensão para uma DSL MEF habilitado

Se você tiver acesso a uma DSL habilitados MEF criado por você ou outra pessoa, você pode escrever extensões para ele.As extensões podem ser usadas para adicionar comandos de menu, manipuladores de gestos ou restrições de validação.Para criar essas extensões, você usar um Visual Studio solução de extensão (VSIX).A solução tem duas partes: um projeto de biblioteca de classe que cria o código assembly e um projeto de VSIX que empacota o assembly.

Para criar uma extensão DSL VSIX

  1. Criar um novo projeto de biblioteca de classes.Para isso, no Novo projeto caixa de diálogo, selecione Visual Basic ou Visual C# e, em seguida, selecione Biblioteca de classe.

  2. No projeto da nova biblioteca de classe, adicione uma referência ao assembly de DSL.

    • Geralmente, este assembly tem um nome que termina com ".DSL.dll".

    • Se você tiver acesso ao projeto do DSL, você pode encontrar o arquivo de assembly sob o diretórioDsl\bin\*

    • Se você tiver acesso ao arquivo VSIX DSL, você poderá encontrar o assembly, alterando a extensão de nome de arquivo do arquivo VSIX para ". zip".Descompacte o arquivo. zip.

  3. Adicione referências para o seguinte.NET assemblies:

    • Microsoft.VisualStudio.Modeling.SDK.11.0.dll

    • Microsoft.VisualStudio.Modeling.SDK.Diagrams.11.0.dll

    • Microsoft.VisualStudio.Modeling.SDK.Shell.11.0.dll

    • System.ComponentModel.Composition.dll

    • DLL

  4. Crie um projeto VSIX na mesma solução.Para isso, no Novo projeto caixa de diálogo caixa, expanda Visual Basic ou Visual C#, clique em extensibilidadee selecione projeto VSIX.

  5. No Solution Explorer, clique com o botão direito no projeto VSIX e clique em Set as StartUp Project.

  6. No novo projeto, abra source.extension.vsixmanifest.

  7. Clique em Adicionar conteúdo.Na caixa de diálogo, defina Tipo de conteúdo para MEF componente, e O projeto de origem ao seu projeto de biblioteca de classe.

  8. Adicione uma referência VSIX ao DSL.

    1. Na source.extension.vsixmanifest, clique em Add Reference

    2. Na caixa de diálogo, clique em Adicionar carga e, em seguida, localize o arquivo VSIX de DSL.O arquivo VSIX é criado na solução de DSL, em DslPackage\bin\*.

      Isso permite que os usuários a instalar o DSL e a sua extensão, ao mesmo tempo.Se o usuário já tiver instalado o DSL, somente sua extensão será instalado.

  9. Revisar e atualizar os outros campos de source.extension.vsixmanifest.Clique em Selecione edições e verifique o correto Visual Studio edições são definidas.

  10. Adicione código para o projeto de biblioteca de classe.Use os exemplos na próxima seção, como um guia.

    Você pode adicionar qualquer número de comando, gesto e classes de validação.

  11. Para testar a extensão, pressione F5.Na instância experimental do Visual Studio, criar ou abrir um arquivo de exemplo de DSL.

Gravando extensões MEF para DSLs

Você pode gravar extensões do projeto de código de assembly de uma solução de extensão separada do DSL.Você também pode usar MEF em seu projeto de DslPackage, como uma maneira conveniente de escrever o código de validação, gestos e comandos como parte de DSL.

Ff972471.collapse_all(pt-br,VS.110).gifComandos de menu

Para escrever um comando de menu, definir uma classe que implementa ICommandExtension e o prefixo da classe com o atributo definido no seu DSL, chamado YourDslCommandExtension.Você pode gravar mais de uma classe de comando de menu.

QueryStatus()é chamado sempre que o usuário clica no diagrama.Ele deve inspecionar a seleção atual e definir command.Enabled para indicar quando o comando é aplicável.

using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl; // My DSL
using Company.MyDsl.ExtensionEnablement; // My DSL
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; // IVsSelectionContext
using Microsoft.VisualStudio.Modeling.ExtensionEnablement; // ICommandExtension

namespace MyMefExtension
{
  // Defined in Dsl\MefExtension\DesignerExtensionMetaDataAttribute.cs:
  [MyDslCommandExtension] 
  public class MyCommandClass : ICommandExtension
  { 
    /// <summary>
    /// Provides access to current document and selection.
    /// </summary>
    [Import]
    IVsSelectionContext SelectionContext { get; set; }

    /// <summary>
    /// Called when the user selects this command.
    /// </summary>
    /// <param name="command"></param>
    public void Execute(IMenuCommand command)
    {
      // Transaction is required if you want to update elements.
      using (Transaction t = SelectionContext.CurrentStore
              .TransactionManager.BeginTransaction("fix names"))
      {
        foreach (ExampleShape shape in SelectionContext.CurrentSelection)
        {
          ExampleElement element = shape.ModelElement as ExampleElement;
          element.Name = element.Name + " !";
        }
        t.Commit();
      }
    }

    /// <summary>
    /// Called when the user right-clicks the diagram.
    /// Determines whether the command should appear.
    /// This method should set command.Enabled and command.Visible.
    /// </summary>
    /// <param name="command"></param>
    public void QueryStatus(IMenuCommand command)
    {
      command.Enabled =
        command.Visible = (SelectionContext.CurrentSelection.OfType<ExampleShape>().Count() > 0);
    }

    /// <summary>
    /// Called when the user right-clicks the diagram.
    /// Determines the text of the command in the menu.
    /// </summary>
    public string Text
    {
      get { return "My menu command"; }
    }
  }
}

Ff972471.collapse_all(pt-br,VS.110).gifGesto manipuladores

Um manipulador de gesto pode lidar com objetos arrastados para o diagrama de qualquer lugar, dentro ou fora de Visual Studio.O exemplo a seguir permite que o usuário arraste os arquivos do Windows Explorer para o diagrama.Ele cria elementos que contêm os nomes de arquivo.

Você pode escrever manipuladores para lidar com gera necessidade de outros modelos DSL e modelos UML.Para obter mais informações, consulte Como: adicionar um manipulador de arrastar-e-soltar.

using System.ComponentModel.Composition;
using System.Linq;
using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling; // Transactions
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; 
using Microsoft.VisualStudio.Modeling.ExtensionEnablement; 

namespace MefExtension
{
  [MyDslGestureExtension]
  class MyGestureExtension : IGestureExtension
  {
    public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
    {
      System.Windows.Forms.MessageBox.Show("double click!");
    }
    
    /// <summary>
    /// Called when the user drags anything over the diagram.
    /// Return true if the dragged object can be dropped on the current target.
    /// </summary>
    /// <param name="targetMergeElement">The shape or diagram that the mouse is currently over</param>
    /// <param name="diagramDragEventArgs">Data about the dragged element.</param>
    /// <returns></returns>
    public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
    {
      // This handler only allows items to be dropped onto the diagram:
      return targetMergeElement is MefDsl2Diagram &&
      // And only accepts files dragged from Windows Explorer:
        diagramDragEventArgs.Data.GetFormats().Contains("FileNameW");
    }


    /// <summary>
    /// Called when the user drops an item onto the diagram.
    /// </summary>
    /// <param name="targetDropElement"></param>
    /// <param name="diagramDragEventArgs"></param>
    public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
    {
      MefDsl2Diagram diagram = targetDropElement as MefDsl2Diagram;
      if (diagram == null) return;

      // This handler only accepts files dragged from Windows Explorer:
      string[] draggedFileNames = diagramDragEventArgs.Data.GetData("FileNameW") as string[];
      if (draggedFileNames == null || draggedFileNames.Length == 0) return; 

      using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("file names"))
      {
        // Create an element to represent each file:
        foreach (string fileName in draggedFileNames)
        {
          ExampleElement element = new ExampleElement(diagram.ModelElement.Partition);
          element.Name = fileName;

          // This method of adding the new element allows the position
          // of the shape to be specified:          
          ElementGroup group = new ElementGroup(element);
          diagram.ElementOperations.MergeElementGroupPrototype(
            diagram, group.CreatePrototype(), PointD.ToPointF(diagramDragEventArgs.MousePosition));
        }
        t.Commit();
      }
    }
  }
}

Ff972471.collapse_all(pt-br,VS.110).gifRestrições de validação

Métodos de validação são marcados pela ValidationExtension atributo que é gerado pelo DSL e também por ValidationMethodAttribute.O método pode aparecer em qualquer classe que não está marcado por um atributo.

Para obter mais informações, consulte Validação em um idioma específico do domínio.

using Company.MyDsl;
using Company.MyDsl.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.Validation;

namespace MefExtension
{
  class MyValidationExtension // Can be any class.
  {
    // SAMPLE VALIDATION METHOD.
    // All validation methods have the following attributes.

    // Specific to the extended DSL:
    [MyDslValidationExtension] 

    // Determines when validation is applied:
    [ValidationMethod(
       ValidationCategories.Save
     | ValidationCategories.Open
     | ValidationCategories.Menu)]
    
    /// <summary>
    /// When validation is executed, this method is invoked
    /// for every element in the model that is an instance
    /// of the second parameter type.
    /// </summary>
    /// <param name="context">For reporting errors</param>
    /// <param name="elementToValidate"></param>
    private void ValidateClassNames
      (ValidationContext context,
       // Type determines to what elements this will be applied:
       ExampleElement elementToValidate)
    { 
      // Write code here to test values and links.
      if (elementToValidate.Name.IndexOf(' ') >= 0)
      {
        // Log any unacceptable values:
        context.LogError(
          // Description:
          "Name must not contain spaces" 
          // Error code unique to this type of error:
          , "MyDsl001" 
          // Element to highlight when user double-clicks error:
          , elementToValidate); 
} } } }

Consulte também

Conceitos

Managed Extensibility Framework (MEF)

Como: adicionar um manipulador de arrastar-e-soltar

Validação em um idioma específico do domínio

Outros recursos

Implantação de VSIX