Partager via


Extension de votre DSL à l'aide de MEF

Vous pouvez exntend votre langage (DSL) spécifique au domaine à l'aide de (MEF) managed extensibility framework. Vous ou d'autres développeurs peut écrire des extensions pour le langage DÉSOLÉ sans modifier la définition et le code du programme DÉSOLÉ. De telles extensions incluent les commandes de menu, les gestionnaires de glisser-déplacer, et la validation. Les utilisateurs peuvent installer votre DÉSOLÉ, puis d'installer éventuellement les extensions pour lui.

En outre, lorsque vous activez MEF dans votre DÉSOLÉ, il peut être plus facile que vous entriez quelques-unes des fonctionnalités de votre DÉSOLÉ, même s'ils sont tous générés avec le langage spécifique à un domaine.

Pour plus d'informations concernant MEF, consultez Managed Extensibility Framework (MEF).

Pour activer votre DÉSOLÉ à étendre par MEF

  1. Créez un dossier nommé MefExtension à l'intérieur de le projet d' DslPackage . Ajoutez les fichiers suivants à celui-ci :

    Nom du fichier

    contenu du fichier

    CommandExtensionVSCT.tt

    Important

    Définissez un GUID dans ce fichier à être identiques GUID CommandSetId définis dans DslPackage \GeneratedCode\Constants application

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

    Si vous ajoutez ce fichier, vous devez activer la validation dans votre DÉSOLÉ en utilisant au moins un des commutateurs dans éditeur \Validation dans l'explorateur DÉSOLÉ.

    <#@ 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" #>
    1. Créez un dossier nommé MefExtension à l'intérieur de le projet d' Dsl . Ajoutez les fichiers suivants à celui-ci :

      Nom du fichier

      Contenu

      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" #>
    2. Ajoutez la ligne suivante au fichier existant nommé DslPackage\Commands.vsct:

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

      insérez la ligne après la directive existante d' <Include> .

    3. ouvrez DslDefinition.dsl.

    4. Dans l'explorateur DÉSOLÉ, sélectionnez éditeur \Validation.

    5. dans la fenêtre Propriétés, assurez-vous qu'au moins une des propriétés nommées Utilise… est true.

    6. Dans la barre d'outils de l'explorateur de solutions, cliquez sur Transformer tous les modèles.

      Les fichiers auxiliaires apparaissent sous chacun des fichiers que vous avez ajoutés.

    7. Générez et exécutez la solution pour vérifier qu'elle fonctionne toujours.

    Votre DÉSOLÉ Force-est maintenant activé. Vous pouvez écrire des commandes de menu, effectuez les gestes des gestionnaires, et des contraintes de validation comme extensions MEF. Vous pouvez écrire ces extensions dans votre solution DÉSOLÉ avec un autre code personnalisé. En outre, vous ou d'autres développeurs peut écrire des extensions distinctes de Visual Studio qui étendent votre DÉSOLÉ.

    Créer une extension pour un DÉSOLÉ Force-activé

    Si vous avez accès à un domaine (Force-activé créé par vous-même ou quelqu'un d'autre, vous pouvez entrer plusieurs extensions pour lui. Les extensions peuvent être utilisées pour ajouter des commandes de menu, les développeurs mouvement des gestionnaires, ou des contraintes de validation. Pour créer ces extensions, vous utilisez une solution de l'extension de Visual Studio (VSIX). La solution a deux parties : un projet de Bibliothèque de classes qui génère l'assembly de code, et un projet VSIX qui assemble l'assembly.

    Pour créer une extension VSIX DÉSOLÉ

    1. Créez un projet Bibliothèque de classes. Pour ce faire, dans la boîte de dialogue de Nouveau projet , sélectionnez Visual Basic ou Visual C# puis sélectionnez Bibliothèque de classes.

    2. Dans le nouveau projet de Bibliothèque de classes, ajoutez une référence à l'assembly de langage spécifique à un domaine.

      • Cet assembly possède généralement un nom qui se termine par « . Dsl.dll ».

      • Si vous avez accès au projet DÉSOLÉ, vous pouvez rechercher le fichier d'assembly dans le répertoire Dsl\bin\*

      • Si vous avez accès au fichier DÉSOLÉ VSIX, vous pouvez trouver l'assembly en modifiant l'extension de nom de fichier du fichier VSIX à « fichier ». Décompressez le fichier .zip.

    3. Ajoutez des références aux assemblys .NET suivants :

      • 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

      • System.Windows.Forms.dll

    4. créez un projet VSIX dans la même solution. Pour ce faire, dans la boîte de dialogue de Nouveau projet , développez Visual Basic ou Visual C#, cliquez sur Extensibilité, puis sélectionnez projet VSIX.

    5. Dans l'explorateur de solutions, cliquez avec le bouton droit sur le projet VSIX puis cliquez sur Définir comme projet de démarrage.

    6. dans le nouveau projet, ouvrez source.extension.vsixmanifest.

    7. Cliquez sur Ajouter du contenu. Dans la boîte de dialogue, définissez Type de contenu à Composant MEF, et Projet source à votre projet de Bibliothèque de classes.

    8. Ajoutez une référence VSIX de langage spécifique à un domaine.

      1. dans source.extension.vsixmanifest, cliquez sur Ajouter une référence

      2. Dans la boîte de dialogue, cliquez sur ajoutez la charge puis localisez le fichier VSIX du langage spécifique à un domaine. Le fichier VSIX est appliqué dans la solution DÉSOLÉ, dans DslPackage\bin\*.

        Cela permet aux utilisateurs d'installer le langage DÉSOLÉ et votre extension en même temps. Si l'utilisateur a déjà installé le DÉSOLÉ, uniquement votre extension est installée.

    9. Révisez et mettez à jour les autres champs d' source.extension.vsixmanifest. Cliquez sur Sélectionner des éditions et vérifiez que les éditions appropriées de Visual Studio sont définies.

    10. Ajoutez le code au projet de Bibliothèque de classes. Utilisez les exemples dans la section suivante conseil.

      Vous pouvez ajouter autant de commande, d'entrée tactile, et les classes de validation.

    11. Pour tester l'extension, appuyez sur F5. Dans l'instance expérimentale de Visual Studio, créez ou ouvrez un fichier d'exemple du langage spécifique à un domaine.

    Extensions MEF d'écriture pour langages spécifiques à un domaine

    Vous pouvez entrer plusieurs extensions dans le projet de code de l'assembly d'une solution différente d'extension DÉSOLÉ. Vous pouvez également utiliser MEF dans votre projet de DslPackage, comme moyen aux touches d'écriture, aux mouvements, et au code de validation dans le cadre de le langage spécifique à un domaine.

    Commandes de menu

    Pour écrire une commande de menu, définissez une classe qui implémente ICommandExtension et le préfixe la classe avec l'attribut défini dans votre DÉSOLÉ, YourDslnomméCommandExtension. Vous pouvez entrer plusieurs classe de commande de menu.

    QueryStatus() est appelé lorsque l'utilisateur clique avec le bouton droit sur le diagramme. Il doit vérifier la sélection et l'ensemble actuel command.Enabled pour indiquer quand la commande s'applique.

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

    Gestionnaires de mouvements

    Un gestionnaire de mouvements peut gérer des objets glissés vers le diagramme n'importe où, intérieur ou à l'extérieur de Visual Studio. L'exemple suivant permet à l'utilisateur de faire glisser des fichiers de l'Explorateur Windows vers le diagramme. Il crée des éléments qui contiennent les noms de fichiers.

    Vous pouvez écrire des gestionnaires pour traiter les faisant glisser d'autres modèles et de modèles UML DÉSOLÉ. Pour plus d'informations, consultez Comment : ajouter un gestionnaire glisser-déplacer.

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

    contraintes de validation

    Les méthodes de validation sont marquées par l'attribut d' ValidationExtension généré par le langage DÉSOLÉ, et par ValidationMethodAttribute. La méthode peut apparaître dans toute classe qui n'est pas marquée par un attribut.

    Pour plus d'informations, consultez Validation dans un langage spécifique à un domaine.

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

    Voir aussi

    Concepts

    Managed Extensibility Framework (MEF)

    Comment : ajouter un gestionnaire glisser-déplacer

    Validation dans un langage spécifique à un domaine

    Autres ressources

    Déploiement VSIX