Estender a DSL usando MEFExtend your DSL by using MEF

Você pode estender sua DSL (linguagem específica de domínio) usando o Managed Extensibility Framework (MEF).You can extend your domain-specific language (DSL) by using Managed Extensibility Framework (MEF). Você ou outros desenvolvedores poderão escrever extensões para a DSL sem alterar a definição de DSL e o código do programa.You or other developers will be able to write extensions for the DSL without changing the DSL definition and program code. Essas extensões incluem comandos de menu, manipuladores de arrastar e soltar e validação.Such extensions include menu commands, drag-and-drop handlers, and validation. Os usuários poderão instalar sua DSL e, opcionalmente, instalar extensões para ela.Users will be able to install your DSL, and then optionally install extensions for it.

Além disso, quando você habilita o MEF em sua DSL, pode ser mais fácil escrever alguns dos recursos de sua DSL, mesmo que eles sejam todos criados com a DSL.In addition, when you enable MEF in your DSL, it can be easier for you to write some of the features of your DSL, even if they are all built together with the DSL.

Para obter mais informações sobre o MEF, consulte Managed Extensibility Framework (MEF).For more information about MEF, see Managed Extensibility Framework (MEF).

Para permitir que sua DSL seja estendida pelo MEFTo enable your DSL to be extended by MEF

  1. Crie uma nova pasta chamada MefExtension dentro do projeto DslPackage .Create a new folder named MefExtension inside the DslPackage project. Adicione os seguintes arquivos a ele:Add the following files to it:

    Nome do arquivo: CommandExtensionVSCT.ttFile name: CommandExtensionVSCT.tt

    Importante

    Defina o GUID nesse arquivo para ser o mesmo que o GUID CommandSetId definido em DslPackage\GeneratedCode\Constants.ttSet the GUID in this file to be the same as the GUID CommandSetId that is defined in 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" #>
    

    Nome do arquivo: CommandExtensionRegistrar.ttFile name: CommandExtensionRegistrar.tt

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

    Nome do arquivo: ValidationExtensionEnablement.ttFile name: ValidationExtensionEnablement.tt

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

    Nome do arquivo: ValidationExtensionRegistrar.ttFile name: ValidationExtensionRegistrar.tt

    Se você adicionar esse arquivo, deverá habilitar a validação em sua DSL usando pelo menos um dos comutadores no EditorValidation no Gerenciador de DSL.If you add this file, you must enable validation in your DSL by using at least one of the switches in EditorValidation in DSL Explorer.

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

    Nome do arquivo: PackageExtensionEnablement.ttFile name: PackageExtensionEnablement.tt

    <#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #>
    <#@ include file="DslPackage\PackageExtensionEnablement.tt" #>
    
  2. Crie uma nova pasta chamada MefExtension dentro do projeto DSL .Create a new folder named MefExtension inside the Dsl project. Adicione os seguintes arquivos a ele:Add the following files to it:

    Nome do arquivo: DesignerExtensionMetaDataAttribute.ttFile name: DesignerExtensionMetaDataAttribute.tt

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

    Nome do arquivo: GestureExtensionEnablement.ttFile name: GestureExtensionEnablement.tt

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

    Nome do arquivo: GestureExtensionController.ttFile name: 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:Add the following line to the existing file that is named DslPackage\Commands.vsct:

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

    Insira a linha após a <Include> diretiva existente.Insert the line after the existing <Include> directive.

  4. Abra DslDefinition. DSL.Open DslDefinition.dsl.

  5. No Gerenciador de DSL, selecione Editor\Validation.In DSL Explorer, select Editor\Validation.

  6. No janela Propriedades, certifique-se de que pelo menos uma das propriedades nomeadas usa seja true .In the Properties window, make sure that at least one of the properties named Uses is true.

  7. Na barra de ferramentas Gerenciador de soluções , clique em transformar todos os modelos.In the Solution Explorer toolbar, click Transform All Templates.

    Os arquivos subsidiários aparecem abaixo de cada um dos arquivos que você adicionou.Subsidiary files appear underneath each of the files that you added.

  8. Compile e execute a solução para verificar se ela ainda está funcionando.Build and run the solution to verify that it is still working.

Sua DSL agora está habilitada para MEF.Your DSL is now MEF-enabled. Você pode escrever comandos de menu, manipuladores de gestos e restrições de validação como extensões de MEF.You can write menu commands, gestures handlers, and validation constraints as MEF extensions. Você pode escrever essas extensões em sua solução de DSL junto com outro código personalizado.You can write these extensions in your DSL solution together with other custom code. Além disso, você ou outros desenvolvedores podem escrever extensões do Visual Studio separadas que estendem sua DSL.In addition, you or other developers can write separate Visual Studio extensions that extend your DSL.

Criar uma extensão para uma DSL habilitada para MEFCreate an extension for a MEF-enabled DSL

Se você tiver acesso a um DSL habilitado para MEF criado por você mesmo ou por outra pessoa, você poderá gravar extensões para ele.If you have access to a MEF-enabled DSL created by yourself or someone else, you can write extensions for it. As extensões podem ser usadas para adicionar comandos de menu, manipuladores de gestos ou restrições de validação.The extensions can be used to add menu commands, gestures handlers, or validation constraints. Para criar essas extensões, você usa uma solução de VSIX (Visual Studio Extension).To author these extensions, you use a Visual Studio extension (VSIX) solution. A solução tem duas partes: um projeto de biblioteca de classes que cria o assembly de código e um projeto VSIX que empacota o assembly.The solution has two parts: a class library project that builds the code assembly, and a VSIX project that packages the assembly.

Para criar um VSIX de extensão de DSLTo create a DSL extension VSIX

  1. Crie um projeto de Biblioteca de Classes.Create a new Class Library project.

  2. No novo projeto, adicione uma referência ao assembly da DSL.In the new project, add a reference to the assembly of the DSL.

    • Esse assembly geralmente tem um nome que termina com ".Dsl.dll".This assembly usually has a name that ends with ".Dsl.dll".

    • Se você tiver acesso ao projeto de DSL, poderá encontrar o arquivo de assembly na pasta de DSL \ \ * do diretórioIf you have access to the DSL project, you can find the assembly file under the directory Dsl\bin\*

    • Se você tiver acesso ao arquivo VSIX de DSL, poderá encontrar o assembly alterando a extensão de nome de arquivo do arquivo VSIX para ". zip".If you have access to the DSL VSIX file, you can find the assembly by changing the file name extension of the VSIX file to ".zip". Descompacte o arquivo. zip.Decompress the .zip file.

  3. Adicione referências aos seguintes assemblies .NET:Add references to the following .NET assemblies:

    • Microsoft.VisualStudio.Modeling.Sdk.11.0.dllMicrosoft.VisualStudio.Modeling.Sdk.11.0.dll

    • Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0.dllMicrosoft.VisualStudio.Modeling.Sdk.Diagrams.11.0.dll

    • Microsoft.VisualStudio.Modeling.Sdk.Shell.11.0.dllMicrosoft.VisualStudio.Modeling.Sdk.Shell.11.0.dll

    • System.ComponentModel.Composition.dllSystem.ComponentModel.Composition.dll

    • System.Windows.Forms.dllSystem.Windows.Forms.dll

  4. Crie um novo projeto de projeto VSIX .Create a new VSIX project project.

  5. Em Gerenciador de soluções, clique com o botão direito do mouse no projeto VSIX e escolha definir como projeto de inicialização.In Solution Explorer, right-click the VSIX project and choose Set as StartUp Project.

  6. No novo projeto, abra Source. Extension. vsixmanifest.In the new project, open source.extension.vsixmanifest.

  7. Clique em adicionar conteúdo.Click Add Content. Na caixa de diálogo, defina tipo de conteúdo para componente MEF e projeto de origem para o projeto de biblioteca de classes.In the dialog box, set Content Type to MEF Component, and Source Project to your class library project.

  8. Adicione uma referência de VSIX ao DSL.Add a VSIX reference to the DSL.

    1. Em origem. extensão. vsixmanifest, clique em Adicionar referênciaIn source.extension.vsixmanifest, click Add Reference

    2. Na caixa de diálogo, clique em Adicionar carga e localize o arquivo VSIX da DSL.In the dialog box, click Add Payload and then locate the VSIX file of the DSL. O arquivo VSIX é criado na solução DSL, no DslPackage \ bin \ *.The VSIX file is built in the DSL solution, in DslPackage\bin\*.

      Isso permite que os usuários instalem a DSL e sua extensão ao mesmo tempo.This lets users install the DSL and your extension at the same time. Se o usuário já tiver instalado a DSL, somente sua extensão será instalada.If the user has already installed the DSL, only your extension will be installed.

  9. Examine e atualize os outros campos de origem. extensão. vsixmanifest.Review and update the other fields of source.extension.vsixmanifest. Clique em selecionar edições e verifique se as edições corretas do Visual Studio estão definidas.Click Select Editions and verify that the correct Visual Studio editions are set.

  10. Adicione código ao projeto de biblioteca de classes.Add code to the class library project. Use os exemplos na próxima seção como guia.Use the examples in the next section as a guide.

    Você pode adicionar qualquer número de classes de comando, de gesto e de validação.You can add any number of command, gesture, and validation classes.

  11. Para testar a extensão, pressione F5.To test the extension, press F5. Na instância experimental do Visual Studio, crie ou abra um arquivo de exemplo da DSL.In the experimental instance of Visual Studio, create or open an example file of the DSL.

Gravando extensões de MEF para DSLsWriting MEF extensions for DSLs

Você pode gravar extensões no projeto de código do assembly de uma solução de extensão de DSL separada.You can write extensions in the assembly code project of a separate DSL extension solution. Você também pode usar o MEF em seu projeto DslPackage, como uma maneira conveniente de escrever comandos, gestos e código de validação como parte da DSL.You can also use MEF in your DslPackage project, as a convenient way to write commands, gestures, and validation code as part of the DSL.

Para escrever um comando de menu, defina uma classe que implemente ICommandExtension e Prefixe a classe com o atributo que é definido em sua DSL, chamado YourDsl CommandExtension .To write a menu command, define a class that implements ICommandExtension and prefix the class with the attribute that is defined in your DSL, named YourDslCommandExtension. Você pode gravar mais de uma classe de comando de menu.You can write more than one menu command class.

QueryStatus() é chamado sempre que o usuário clica com o botão direito do mouse no diagrama.QueryStatus() is called whenever the user right-clicks the diagram. Ele deve inspecionar a seleção atual e definir command.Enabled para indicar quando o comando é aplicável.It should inspect the current selection and set command.Enabled to indicate when the command is applicable.

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"; }
    }
  }
}

Manipuladores de gestosGesture Handlers

Um manipulador de gestos pode lidar com objetos arrastados para o diagrama de qualquer lugar, dentro ou fora do Visual Studio.A gesture handler can deal with objects dragged onto the diagram from anywhere, inside or outside Visual Studio. O exemplo a seguir permite que o usuário arraste arquivos do Windows Explorer para o diagrama.The following example lets the user drag files from Windows Explorer onto the diagram. Ele cria elementos que contêm os nomes de arquivo.It creates elements that contain the file names.

Você pode escrever manipuladores para lidar com arrastar de outros modelos de DSL e modelos UML.You can write handlers to deal with drags from other DSL models and UML models. Para obter mais informações, consulte como adicionar um manipulador de arrastar e soltar.For more information, see How to: Add a Drag-and-Drop Handler.

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();
      }
    }
  }
}

Restrições de validaçãoValidation constraints

Os métodos de validação são marcados pelo ValidationExtension atributo que é gerado pela DSL e também por ValidationMethodAttribute .Validation methods are marked by the ValidationExtension attribute that is generated by the DSL, and also by ValidationMethodAttribute. O método pode aparecer em qualquer classe que não esteja marcada por um atributo.The method can appear in any class that is not marked by an attribute.

Para obter mais informações, consulte validação em um idioma de Domain-Specific.For more information, see Validation in a Domain-Specific Language.

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);
} } } }

Confira tambémSee also