Partager via


Comment : définir un gestionnaire de mouvements sur un diagramme de modélisation

Dans Visual Studio Ultimate, il vous est possible de définir des commandes exécutées lorsque l'utilisateur double-clique ou fait glisser des éléments sur un diagramme UML. Il vous est possible d'empaqueter ces extensions dans une extension d'intégration Visual Studio (VSIX) et les distribuer à d'autres utilisateurs de Visual Studio Ultimate.

Si un comportement intégré existe déjà pour le type de diagramme et le type d'élément que vous souhaitez faire glisser, vous risquez de ne pas pouvoir effectuer d'ajouts à ce comportement ni de le substituer.

Configuration requise

Création d'un gestionnaire de mouvements

Pour définir un gestionnaire de mouvements pour un concepteur UML, vous devez créer une classe qui définisse le comportement du gestionnaire de mouvements, puis incorporer cette classe à une extension d'intégration Visual Studio (VSIX). L'extension d'intégration Visual Studio (VSIX) joue le rôle d'un conteneur capable d'installer le gestionnaire. Il existe deux autres méthodes pour définir un gestionnaire de mouvements :

  • Créez un gestionnaire de mouvements dans son propre projet VSIX à l'aide d'un modèle de projet. Il s'agit de la méthode la plus rapide. Choisissez cette méthode si vous ne souhaitez pas combiner votre gestionnaire avec d'autres types d'extensions, telles que les extensions de validation, les éléments de boîte à outils personnalisés ou les commandes de menu.

  • Créez séparément les gestionnaires de mouvements et les projets VSIX. Choisissez cette méthode si vous souhaitez combiner plusieurs types d'extensions au sein d'un même projet VSIX. Par exemple, si votre gestionnaire de mouvements prévoit que le modèle observe des contraintes spécifiques, vous pouvez l'incorporer au même projet VSIX en tant que méthode de validation.

Pour créer un gestionnaire de mouvements dans son propre projet VSIX

  1. Dans la boîte de dialogue Nouveau projet, sous Modèles installés, sélectionnez Extension de mouvement.

  2. Ouvrez le fichier .cs du nouveau projet et modifiez la classe GestureExtension pour implémenter votre gestionnaire de mouvements.

    Pour plus d'informations, consultez Implémentation du gestionnaire de mouvements.

  3. Testez le gestionnaire de mouvements en appuyant sur F5. Pour plus d'informations, consultez Exécution du gestionnaire de mouvements.

  4. Installez le gestionnaire de mouvements sur un autre ordinateur en copiant le fichier bin\*\*.vsix généré par votre projet. Pour plus d'informations, consultez Installation du gestionnaire de mouvements.

Voici une procédure alternative :

Pour créer un projet distinct de bibliothèque de classes (DLL) pour le gestionnaire de mouvements

  1. Créez un projet de bibliothèque de classes dans une nouvelle solution Visual Studio ou dans une solution existante.

    1. Dans le menu Fichier, cliquez sur Nouveau, Projet.

    2. Sous Modèles installés, cliquez sur Visual C# ou Visual Basic, puis dans la colonne centrale, cliquez sur Bibliothèque de classes.

  2. Ajoutez les références suivantes à votre projet.

    Microsoft.VisualStudio.Modeling.Sdk.12.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.12.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

    System.Windows.Forms

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer. Vous n'en aurez besoin que si vous devez étendre des diagrammes de couche. Pour plus d'informations, consultez Extension des diagrammes de couche.

  3. Ajoutez au projet un fichier de classe comportant le code suivant.

    Notes

    Adaptez le nom de la classe et de l'espace de noms à vos besoins.

    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
    using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Uml.Classes;
    // ADD other UML namespaces if required
    
    namespace MyGestureHandler // CHANGE
    {
      // DELETE any of these attributes if the handler
      // should not work with some types of diagram.
      [ClassDesignerExtension]
      [ActivityDesignerExtension]
      [ComponentDesignerExtension]
      [SequenceDesignerExtension]
      [UseCaseDesignerExtension]
      // [LayerDesignerExtension]
    
      // Gesture handlers must export IGestureExtension:
      [Export(typeof(IGestureExtension))]
      // CHANGE class name
      public class MyGesture1 : IGestureExtension
      {
        [Import]
        public IDiagramContext DiagramContext { get; set; }
    
        /// <summary>
        /// Called when the user double-clicks on the diagram
        /// </summary>
        /// <param name="targetElement"></param>
        /// <param name="diagramPointEventArgs"></param>
        public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target shape, if any. Null if the target is the diagram.
          IShape targetIShape = targetElement.CreateIShape();
    
          // Do something...
        }
    
        /// <summary>
        /// Called repeatedly when the user drags from anywhere on the screen.
        /// Return value should indicate whether a drop here is allowed.
        /// </summary>
        /// <param name="targetMergeElement">References the element to be dropped on.</param>
        /// <param name="diagramDragEventArgs">References the element to be dropped.</param>
        /// <returns></returns>
        public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target element, if any. Null if the target is the diagram.
          IShape targetIShape = targetMergeElement.CreateIShape();
    
          // This example allows drag of any UML elements.
          return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0;
        }
    
    
        /// <summary>
        /// Execute the action to be performed on the drop.
        /// </summary>
        /// <param name="targetDropElement"></param>
        /// <param name="diagramDragEventArgs"></param>
        public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
        }
    
        /// <summary>
        /// Retrieves UML IElements from drag arguments.
        /// Works for drags from UML diagrams.
        /// </summary>
        private IEnumerable<IElement> GetModelElementsFromDragEvent
                (DiagramDragEventArgs dragEvent)
        {
          //ElementGroupPrototype is the container for
          //dragged and copied elements and toolbox items.
          ElementGroupPrototype prototype =
             dragEvent.Data.
             GetData(typeof(ElementGroupPrototype))
                  as ElementGroupPrototype;
          // Locate the originals in the implementation store.
          IElementDirectory implementationDirectory =
             dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
    
          return prototype.ProtoElements.Select(
            prototypeElement =>
            {
              ModelElement element = implementationDirectory
                .FindElement(prototypeElement.ElementId);
              ShapeElement shapeElement = element as ShapeElement;
              if (shapeElement != null)
              {
                // Dragged from a diagram.
                return shapeElement.ModelElement as IElement;
              }
              else
              {
                // Dragged from UML Model Explorer.
                return element as IElement;
              }
            });
        }
    
      }
    }
    

    Pour plus d'informations sur les éléments à ajouter dans les méthodes, consultez Implémentation du gestionnaire de mouvements.

Vous devez ajouter votre commande de menu à un projet VSIX, qui jouera le rôle de conteneur pour l'installation de la commande. Si vous le souhaitez, vous pouvez inclure d'autres composants dans le même fichier VSIX.

Pour ajouter un gestionnaire de mouvements distinct à un projet VSIX

  1. Cette procédure n'est pas nécessaire si vous avez créé la gestion de mouvement avec son propre VSIX.

  2. Créez un projet VSIX, sauf si votre solution en comporte déjà un.

    1. Dans Explorateur de solutions, dans le menu contextuel de la solution, choisissez Ajouter, Nouveau projet.

    2. Sous Modèles installés, développez Visual C# ou Visual Basic, puis sélectionnez Extensibilité. Dans la colonne centrale, choisissez Projet VSIX.

  3. Définissez le projet VSIX comme projet de démarrage de la solution.

    • Dans l'Explorateur de solutions, dans le menu contextuel du projet VSIX, choisissez En faire un objet de démarrage.
  4. Dans source.extension.vsixmanifest, ajoutez le projet de bibliothèque de classes du gestionnaire de mouvements en tant que composant MEF.

    1. Sous l'onglet Métadonnées, définissez un nom pour le package VSIX.

    2. Sous l'onglet Installer les cibles, définissez Visual Studio Ultimate et Premium comme cibles.

    3. Sous l'onglet Composants, choisissez Nouveau, et dans la boîte de dialogue, définissez :

      Type = Composant MEF

      Source = Projet dans la solution actuelle

      Projet = Your class library project

Exécution du gestionnaire de mouvements

À des fins de test, exécutez votre gestionnaire de mouvements en mode débogage.

Pour tester le gestionnaire de mouvements

  1. Appuyez sur F5, ou dans le menu Déboguer, cliquez sur Démarrer le débogage.

    Une instance expérimentale de Visual Studio démarre alors.

    Résolution des problèmes : Si un nouveau projet Visual Studio ne démarre pas :

    • Si vous avez plusieurs projets, assurez-vous que le projet VSIX est défini comme projet de démarrage de la solution.

    • Dans l'Explorateur de solutions, dans le menu contextuel du projet testé, choisissez Propriétés. Dans l'éditeur de propriétés du projet, cliquez sur l'onglet Déboguer. Assurez-vous que la chaîne présente dans le champ Démarrer le programme externe correspond au chemin d'accès complet de Visual Studio, généralement :

      C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe

  2. Dans l'instance expérimentale de Visual Studio, ouvrez ou créez un projet de modélisation, puis ouvrez ou créez un diagramme de modélisation. Utilisez un diagramme qui appartient à l'un des types répertoriés dans les attributs de la classe de votre gestionnaire de mouvements.

  3. Double-cliquez sur le diagramme. Votre gestionnaire de double-clics doit être appelé.

  4. Faites glisser un élément de l'explorateur UML sur le diagramme. Votre gestionnaire de glisser-déplacer doit être appelé.

Résolution des problèmes : si le gestionnaire de mouvements ne fonctionne pas, assurez-vous que :

  • Le projet du gestionnaire de mouvements est répertorié en tant que composant MEF dans l'onglet Composants de source.extensions.manifest dans le projet VSIX ;

  • les paramètres de tous les attributs Import et Export sont valides ;

  • la méthode CanDragDrop ne retourne pas la valeur false ;

  • le type de diagramme de modèle que vous utilisez (séquence ou classe UML, par exemple) est répertorié comme étant l'un des attributs de la classe du gestionnaire de mouvements [ClassDesignerExtension], [SequenceDesignerExtension], etc. ;

  • aucune fonctionnalité intégrée n'est déjà définie pour ce type de cible et d'élément déposé.

Implémentation du gestionnaire de mouvements

Méthodes du gestionnaire de mouvements

La classe du gestionnaire de mouvements implémente et exporte IGestureExtension. Les méthodes que vous devez définir se présentent comme suit :

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Retournez la valeur true pour autoriser le déplacement de l'élément source référencé dans dragEvent vers cette cible.

Cette méthode ne doit pas apporter de modifications au modèle. Elle doit fonctionner rapidement, car elle permet de déterminer l'état de la flèche à mesure que l'utilisateur déplace la souris.

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Mettez à jour le modèle en fonction de l'objet source référencé dans dragEvent et la cible.

Appelé lorsque l'utilisateur relâche le bouton de la souris après avoir effectué un glisser.

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target est la forme sur laquelle l'utilisateur a double-cliqué.

Vous pouvez écrire des gestionnaires qui peuvent accepter non seulement des éléments UML, mais également une vaste gamme d'autres éléments, comme les fichiers, les nœuds d'un affichage de classes .NET, les nœuds du navigateur de l'architecture, etc. L'utilisateur peut faire glisser l'un de ces éléments dans un diagramme UML, à condition que vous écriviez une méthode OnDragDrop capable de décoder la forme sérialisée des éléments. Les méthodes de décodage varient d'un type d'élément à l'autre.

Les paramètres de ces méthodes sont :

  • ShapeElement target. Forme ou diagramme sur lequel l'utilisateur a fait glisser quelque chose.

    ShapeElement est une classe dans l'implémentation qui est sous-jacente aux outils de modélisation UML. Pour réduire le risque de mettre le modèle UML et les diagrammes dans un état incohérent, nous vous recommandons de ne pas utiliser directement les méthodes de cette classe. À la place, incluez l'élément dans un wrapper dans un IShape, puis utilisez les méthodes décrites dans Comment : afficher un modèle sur des diagrammes.

    • Pour obtenir un IShape :

      IShape targetIShape = target.CreateIShape(target);
      
    • Pour obtenir l'élément de modèle ciblé par l'opération glisser ou double-clic :

      IElement target = targetIShape.Element;
      

      Vous pouvez le caster en un type d'élément plus spécifique.

    • Pour obtenir le magasin de modèles UML qui contient le modèle UML :

      IModelStore modelStore = 
        targetIShape.Element.GetModelStore(); 
      
    • Pour obtenir l'accès à l'hôte et au fournisseur de services :

      target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
      
  • DiagramDragEventArgs eventArgs. Ce paramètre achemine la forme sérialisée de l'objet source d'une opération glisser :

    System.Windows.Forms.IDataObject data = eventArgs.Data;  
    

    Vous pouvez faire glisser des éléments de nombreux genres différents vers un diagramme, à partir de différentes parties de Visual Studio, ou à partir du Bureau Windows. Différents types d'éléments sont encodés de façons différentes dans IDataObject. Pour en extraire les éléments, reportez-vous à la documentation correspondant au type d'objet approprié.

    Si votre objet source est un élément UML qui a été glissé à partir de l'explorateur de modèles UML ou d'un autre diagramme UML, consultez Comment : obtenir de l'interface IDataObject des éléments de modèles UML.

Écriture du code des méthodes

Pour plus d'informations sur l'écriture du code permettant de lire et de mettre à jour le modèle, consultez Programmation à l'aide de l'API UML.

Pour plus d'informations sur l'accès aux informations de modèle dans une opération de glissement, consultez Comment : obtenir de l'interface IDataObject des éléments de modèles UML.

Si vous utilisez un diagramme de séquence, consultez également Comment : modifier des diagrammes de séquence à l'aide de l'API UML.

Outre les paramètres des méthodes, vous pouvez également déclarer une propriété importée dans votre classe qui fournit l'accès au diagramme et au modèle actuels.

[Import] public IDiagramContext DiagramContext { get; set; }

La déclaration d'IDiagramContext vous permet d'écrire du code dans vos méthodes qui accède au diagramme, à la sélection actuelle et au modèle :

IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}

Pour plus d'informations, consultez Comment : naviguer dans le modèle UML.

Installation et désinstallation d'une extension

Vous pouvez installer une extension Visual Studio sur votre propre ordinateur et sur d'autres.

Pour installer une extension

  1. Sur votre ordinateur, recherchez le fichier .vsix qui a été généré par votre projet VSIX.

    1. Dans Explorateur de solutions, dans le menu contextuel du projet VSIX, choisissez Ouvrir le dossier dans l'Explorateur Windows.

    2. Localisez le fichier bin\*\YourProject.vsix

  2. Copiez le fichier .vsix sur l'ordinateur cible sur lequel vous souhaitez installer l'extension. Il peut s'agir de votre propre ordinateur ou d'un autre.

    L'ordinateur cible doit disposer de l'une des éditions de Visual Studio que vous avez spécifiées dans source.extension.vsixmanifest.

  3. Sur l'ordinateur cible, ouvrez le fichier .vsix.

    Le Programme d'installation des extensions Visual Studio ouvre et installe l'extension.

  4. Démarrez ou redémarrez Visual Studio.

Pour désinstaller une extension

  1. Dans le menu Outils, cliquez sur Gestionnaire d'extensions....

  2. Développez Extensions installées.

  3. Sélectionnez l'extension, puis cliquez sur Désinstaller.

Exceptionnellement, une extension défaillante ne parvient pas à se charger et crée un rapport dans la fenêtre d'erreur, mais ne s'affiche pas dans le gestionnaire d'extensions. Dans ce cas, vous pouvez supprimer l'extension en supprimant le fichier de :

%LocalAppData%\Local\Microsoft\VisualStudio\12.0\Extensions

Exemple

L'exemple suivant indique comment créer des lignes de vie dans un diagramme de séquence, en fonction des parties et des ports d'un composant glissé à partir d'un diagramme de composant.

Pour le tester, appuyez sur F5. Une instance expérimentale de Visual Studio s'ouvre. Dans cette instance, ouvrez un modèle UML et créez un composant sur un diagramme de composant. Ajoutez à ce composant quelques interfaces et éléments internes de composant. Sélectionnez les interfaces et les parties. Faites ensuite glisser les interfaces et les parties sur un diagramme de séquence. Pour ce faire, effectuez un glisser du diagramme de composant sur l'onglet du diagramme de séquence, puis sur le diagramme de séquence en question. Une ligne de vie s'affichera pour chaque interface et chaque partie.

Pour plus d'informations sur la liaison d'interactions à des diagrammes de séquence, consultez Comment : modifier des diagrammes de séquence à l'aide de l'API UML.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;

/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
  [Import]
  public IDiagramContext Context { get; set; }

  /// <summary>
  /// Called by the modeling framework when
  /// the user drops something on a target.
  /// </summary>
  /// <param name="target">The target shape or diagram </param>
  /// <param name="dragEvent">The item being dragged</param>
  public void OnDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    ISequenceDiagram diagram = Context.CurrentDiagram
            as ISequenceDiagram;
    IInteraction interaction = diagram.Interaction;
    if (interaction == null)
    {
      // Sequence diagram is empty: create an interaction.
      interaction = diagram.ModelStore.Root.CreateInteraction();
      interaction.Name = Context.CurrentDiagram.Name;
      diagram.Bind(interaction);
    }
    foreach (IConnectableElement connectable in
       GetConnectablesFromDrag(dragEvent))
    {
      ILifeline lifeline = interaction.CreateLifeline();
      lifeline.Represents = connectable;
      lifeline.Name = connectable.Name;
    }
  }

  /// <summary>
  /// Called by the modeling framework to determine whether
  /// the user can drop something on a target.
  /// Must not change anything.
  /// </summary>
  /// <param name="target">The target shape or diagram</param>
  /// <param name="dragEvent">The item being dragged</param>
  /// <returns>true if this item can be dropped on this target</returns>
  public bool CanDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
    return connectables.Count() > 0;
  }

  ///<summary>
  /// Get dragged parts and ports of an IComponent.
  ///</summary>
  private IEnumerable<IConnectableElement>
    GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
  {
    foreach (IElement element in
      GetModelElementsFromDragEvent(dragEvent))
    {
      IConnectableElement part = element as IConnectableElement;
      if (part != null)
      {
        yield return part;
      }
    }
  }

  /// <summary>
  /// Retrieves UML IElements from drag arguments.
  /// Works for drags from UML diagrams.
  /// </summary>
  private IEnumerable<IElement> GetModelElementsFromDragEvent
          (DiagramDragEventArgs dragEvent)
  {
    //ElementGroupPrototype is the container for
    //dragged and copied elements and toolbox items.
    ElementGroupPrototype prototype =
       dragEvent.Data.
       GetData(typeof(ElementGroupPrototype))
            as ElementGroupPrototype;
    // Locate the originals in the implementation store.
    IElementDirectory implementationDirectory =
       dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;

    return prototype.ProtoElements.Select(
      prototypeElement =>
      {
        ModelElement element = implementationDirectory
          .FindElement(prototypeElement.ElementId);
        ShapeElement shapeElement = element as ShapeElement;
        if (shapeElement != null)
        {
          // Dragged from a diagram.
          return shapeElement.ModelElement as IElement;
        }
        else
        {
          // Dragged from UML Model Explorer.
          return element as IElement;
        }
      });
  }

  public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
  {
  }
}

Le code de GetModelElementsFromDragEvent() est décrit dans Comment : obtenir de l'interface IDataObject des éléments de modèles UML.

Voir aussi

Concepts

Comment : définir et installer une extension de modélisation

Extension de modèles et de diagrammes UML

Comment : définir une commande de menu sur un diagramme de modélisation

Comment : définir des contraintes de validation pour les modèles UML

Programmation à l'aide de l'API UML