Comment : ajouter un gestionnaire glisser-déplacerHow to: Add a Drag-and-Drop Handler

Vous pouvez ajouter des gestionnaires pour les événements glisser-déplacer à votre DSL, de telle sorte que les utilisateurs puissent faire glisser des éléments vers votre diagramme à partir d'autres diagrammes ou d'autres parties de Visual StudioVisual Studio.You can add handlers for drag-and-drop events to your DSL, so that users can drag items onto your diagram from other diagrams or from other parts of Visual StudioVisual Studio. Vous pouvez aussi ajouter des gestionnaires pour des événements tels que les doubles clics.You can also add handlers for events such as double-clicks. Ensemble, glisser-déplacer et double-cliquez sur les gestionnaires sont appelés les gestionnaires de mouvements.Together, drag-and-drop and double-click handlers are known as gesture handlers.

Cette rubrique traite des mouvements de type glisser-déplacer dont l'origine se situe sur d'autres diagrammes.This topic discusses drag-and-drop gestures that originate on other diagrams. Pour déplacer et copier des événements au sein d'un seul diagramme, pensez à l'autre solution qui consiste à définir une sous-classe d'ElementOperations.For move and copy events within a single diagram, consider the alternative of defining a subclass of ElementOperations. Pour plus d’informations, consultez personnalisation de comportement de copie.For more information, see Customizing Copy Behavior. Vous avez aussi la possibilité de personnaliser la définition DSL.You might also be able to customize the DSL definition.

Dans cette rubriqueIn this topic

Définition de gestionnaires de mouvements en substituant les méthodes ShapeElementDefining Gesture Handlers by Overriding ShapeElement Methods

Ajoutez un nouveau fichier de code à votre projet DSL.Add a new code file to your DSL project. Pour un gestionnaire d'événements, vous devez avoir au moins les instructions using suivantes :For a gesture handler, you usually must have at least the following using statements:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Linq;

Dans le nouveau fichier, définissez une classe partielle pour la forme ou la classe de diagramme qui doit répondre à l'opération de déplacement.In the new file, define a partial class for the shape or diagram class that should respond to the drag operation. Remplacez les méthodes suivantes :Override the following methods:

  • OnDragOver- Cette méthode est appelée lorsque le pointeur de la souris entre dans la forme pendant une opération de déplacement.OnDragOver- This method is called when the mouse pointer enters the shape during a drag operation. Votre méthode doit examiner l'élément que l'utilisateur déplace et définir la propriété Effect pour indiquer si l'utilisateur peut déposer l'élément sur cette forme.Your method should inspect the item that the user is dragging, and set the Effect property to indicate whether the user can drop the item on this shape. La propriété Effect détermine l'aspect du curseur pendant qu'il est sur la forme, ainsi que le fait de savoir si OnDragDrop() est appelé quand l'utilisateur relâche le bouton de la souris.The Effect property determines the appearance of the cursor while it is over this shape, and also determines whether OnDragDrop() will be called when the user releases the mouse button.

    partial class MyShape // MyShape generated from DSL Definition.
    {
        public override void OnDragOver(DiagramDragEventArgs e)
        {
          base.OnDragOver(e);
          if (e.Effect == System.Windows.Forms.DragDropEffects.None
               && IsAcceptableDropItem(e)) // To be defined
          {
            e.Effect = System.Windows.Forms.DragDropEffects.Copy;
          }
        }
    
  • OnDragDrop -Cette méthode est appelée si l’utilisateur relâche le bouton de la souris lorsque le pointeur est sur ce diagramme, une forme ou si OnDragOver(DiagramDragEventArgs e) défini précédemment e.Effect à une valeur autre que None.OnDragDrop - This method is called if the user releases the mouse button while the mouse pointer rests over this shape or diagram, if OnDragOver(DiagramDragEventArgs e) previously set e.Effect to a value other than None.

    public override void OnDragDrop(DiagramDragEventArgs e)
        {
          if (!IsAcceptableDropItem(e))
          {
            base.OnDragDrop(e);
          }
          else
          { // Process the dragged item, for example merging a copy into the diagram
            ProcessDragDropItem(e); // To be defined
          }
        }
    
  • OnDoubleClick -Cette méthode est appelée lorsque l’utilisateur double-clique sur la forme ou le schéma.OnDoubleClick - This method is called when the user double-clicks the shape or diagram.

    Pour plus d’informations, consultez Comment : intercepter un clic sur une forme ou un élément décoratif.For more information, see How to: Intercept a Click on a Shape or Decorator.

    Définissez IsAcceptableDropItem(e) pour déterminer si l'élément déplacé est acceptable et ProcessDragDropItem(e) pour mettre à jour votre modèle quand l'élément est déposé.Define IsAcceptableDropItem(e) to determine whether the dragged item is acceptable, and ProcessDragDropItem(e) to update your model when the item is dropped. Ces méthodes doivent d'abord extraire l'élément des arguments de l'événement.These methods must first extract the item from the event arguments. Pour plus d’informations sur la procédure à suivre, consultez comment obtenir une référence à l’élément glissé.For information about how to do that, see How to get a reference to the dragged item.

Définition de gestionnaires de mouvements à l’aide de MEFDefining Gesture Handlers by using MEF

MEF (Managed Extensibility Framework) vous permet de définir des composants qui peuvent être installés avec une configuration minimale.MEF (Managed Extensibility Framework) lets you define components that can be installed with minimal configuration. Pour plus d’informations, consultez Vue d’ensemble de Managed Extensibility Framework.For more information, see Managed Extensibility Framework (MEF).

Pour définir un gestionnaire d'événements MEFTo define a MEF gesture handler

  1. Ajouter à votre Dsl et DslPackage projets le MefExtension les fichiers qui sont décrites dans étendre votre DSL à l’aide de MEF.Add to your Dsl and DslPackage projects the MefExtension files that are described in Extend your DSL by using MEF.

  2. Vous pouvez désormais définir un gestionnaire d'événements comme composant MEF :You can now define a gesture handler as a MEF component:

    
    // This attribute is defined in the generated file
    // DslPackage\MefExtension\DesignerExtensionMetaDataAttribute.cs:
    [MyDslGestureExtension]
    public class MyGestureHandlerClassName : IGestureExtension
    {
      /// <summary>
      /// Called to determine whether a drag onto the diagram can be accepted.
      /// </summary>
      /// <param name="diagramDragEventArgs">Contains a link to the item that is being dragged</param>
      /// <param name="targetMergeElement">The shape or connector that the mouse is over</param>
      /// <returns>True if the item can be accepted on the targetMergeElement.</returns>
      public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
      {
        MyShape target = targetMergeElement as MyShape;
        if (target == null) return false;
        if (target.IsAcceptableDropItem(diagramDragEventArgs)) return true;
        return false;
      }
      public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
      {
        MyShape target = targetMergeElement as MyShape;
        if (target == null || ! target.IsAcceptableDropItem(diagramDragEventArgs)) return;
        // Process the dragged item, for example merging a copy into the diagram:
        target.ProcessDragDropItem(diagramDragEventArgs);
     }
    

    Vous pouvez créer plusieurs composants de gestionnaire de mouvements, comme lorsque vous avez différents types d'objets déplacés.You can create more than one gesture handler component, such as when you have different types of dragged objects.

  3. Ajoutez les définitions de classe partielle pour la forme cible, les classes de connecteurs ou de diagrammes, et définissez les méthodes IsAcceptableDropItem() et ProcessDragDropItem().Add partial class definitions for the target shape, connector or diagram classes, and define the methods IsAcceptableDropItem() and ProcessDragDropItem(). Ces méthodes doivent commencer par extraire l'élément déplacé des arguments de l'événement.These methods must begin by extracting the dragged item from the event arguments. Pour plus d’informations, consultez comment obtenir une référence à l’élément glissé.For more information, see How to get a reference to the dragged item.

Comment faire pour décoder l’élément déplacéHow to decode the dragged item

Lorsque l'utilisateur déplace un élément sur votre diagramme, ou d'une partie de votre diagramme vers une autre, les informations sur l'élément déplacé sont disponibles dans DiagramDragEventArgs.When the user drags an item onto your diagram, or from one part of your diagram to another, information about the item that is being dragged is available in DiagramDragEventArgs. Comme l'opération de déplacement peut avoir démarré sur n'importe quel objet de l'écran, les données peuvent être disponibles dans l'un des nombreux formats existants.Because the drag operation could have started at any object on the screen, the data can be available in any one of a variety of formats. Votre code doit identifier les formats qu'il est capable de gérer.Your code must recognize the formats with which it is capable of dealing.

Pour connaître les formats dans lesquels vos informations sur la source du déplacement sont disponibles, exécutez votre code en mode débogage, en définissant un point d'arrêt à l'entrée de OnDragOver() ou CanDragDrop().To discover the formats in which your drag source information is available, run your code in debugging mode, setting a breakpoint at the entry to OnDragOver() or CanDragDrop(). Examinez les valeurs du paramètre DiagramDragEventArgs.Inspect the values of the DiagramDragEventArgs parameter. Les informations sont fournies sous deux formes :The information is provided in two forms:

  • IDataObject Data -Cette propriété comporte généralement des versions sérialisées des objets source, dans plusieurs formats.IDataObject Data - This property carries serialized versions of the source objects, usually in more than one format. Ses fonctions les plus utiles sont les suivantes :Its most useful functions are:

    • diagramEventArgs.Data.GetDataFormats() - répertorie les formats capable de décoder l’objet déplacé.diagramEventArgs.Data.GetDataFormats() - Lists the formats in which you can decode the dragged object. Par exemple, si l'utilisateur déplace un fichier à partir du Bureau, les formats disponibles incluent le nom de fichier (« FileNameW »).For example, if the user drags a file from the desktop, the available formats include the file name ("FileNameW").

    • diagramEventArgs.Data.GetData(format) -Décode l’objet dans le format spécifié.diagramEventArgs.Data.GetData(format) - Decodes the dragged object in the specified format. Effectuez une conversion de type de l'objet dans le type approprié.Cast the object to the appropriate type. Par exemple :For example:

      string fileName = diagramEventArgs.Data.GetData("FileNameW") as string;

      Vous pouvez aussi transmettre des objets tels que les références de bus de modèles à partir de la source et dans votre propre format personnalisé.You can also transmit objects such as model bus references from the source in your own custom format. Pour plus d’informations, consultez comment envoyer des références de Bus de modèle dans un glisser -déplacer.For more information, see How to Send Model Bus References in a Drag and Drop.

  • ElementGroupPrototype Prototype -Utilisez cette propriété si vous souhaitez que les utilisateurs à faire glisser des éléments à partir d’une ligne DSL ou un modèle UML.ElementGroupPrototype Prototype - Use this property if you want users to drag items from a DSL or a UML model. Un prototype de groupe d'éléments contient un ou plusieurs objets, les liens et les valeurs de leurs propriétés.An element group prototype contains one or more objects, links, and their property values. Il est également utilisé dans les opérations de collage et lorsque vous ajoutez un élément à partir de la boîte à outils.It is also used in paste operations and when you are adding an element from the toolbox. Dans un prototype, les objets et leurs types sont identifiés par un GUID.In a prototype, objects and their types are identified by Guid. Par exemple, ce code permet à l'utilisateur de déplacer les éléments de classe à partir d'un diagramme UML ou de l'Explorateur de modèles UML :For example, this code allows the user to drag class elements from a UML diagram or UML Model Explorer:

    private bool IsAcceptableDropItem(DiagramDragEventArgs e)
    {
      return e.Prototype != null && e.Prototype.RootProtoElements.Any(element =>
            element.DomainClassId.ToString()
            == "3866d10c-cc4e-438b-b46f-bb24380e1678"); // Accept UML class shapes.
     // Or, from another DSL: SourceNamespace.SourceShapeClass.DomainClassId
    }
    

    Pour accepter les formes UML, déterminez par expérience les GUID des classes de formes UML.To accept UML shapes, determine the Guids of the UML shape classes by experiment. N'oubliez qu'il existe généralement plusieurs types d'éléments sur un diagramme.Remember that there is usually more than one type of element on any diagram. Souvenez-vous aussi qu'un objet déplacé à partir d'un diagramme DSL ou UML est la forme, et non l'élément de modèle.Remember also that an object dragged from a DSL or UML diagram is the shape, not the model element.

    DiagramDragEventArgs possède aussi les propriétés qui indiquent la position actuelle du pointeur de la souris et si l'utilisateur appuie sur les touches CTRL, ALT ou MAJ.DiagramDragEventArgs also has properties that indicate the current mouse pointer position and whether the user is pressing the CTRL, ALT, or SHIFT keys.

Obtention d’un élément glissé d’origineHow to get the original of a dragged element

Les propriétés Data et Prototype des arguments de l'événement contiennent uniquement une référence à la forme déplacée.The Data and Prototype properties of the event arguments contain only a reference to the dragged shape. Généralement, si vous voulez créer un objet dans le DSL cible dérivé du prototype d'une quelconque façon, vous devez obtenir l'accès à l'original, par exemple en lisant le contenu du fichier ou en accédant à l'élément de modèle représenté par une forme.Usually, if you want to create an object in the target DSL that is derived from the prototype in some way, you need to obtain access to the original, for example, reading the file contents, or navigating to the model element represented by a shape. Vous pouvez à cette fin utiliser l'extension Visual Studio Model Bus.You can use Visual Studio Model Bus to help with this.

Pour préparer un projet DSL pour le bus de modèlesTo prepare a DSL project for Model Bus

  1. Rendez le DSL source accessible par Visual StudioVisual Studio Model Bus :Make the source DSL accessible by Visual StudioVisual Studio Model Bus:

    1. Téléchargez et installez l'extension Visual Studio Model Bus, si ce n'est déjà fait.Download and install the Visual Studio Model Bus extension, if it is not already installed. Pour plus d’informations, consultez Visualization and Modeling SDK.For more information, see Visualization and Modeling SDK.

    2. Ouvrez le fichier de définition DSL du DSL source dans le concepteur DSL.Open the DSL definition file of the source DSL in DSL Designer. Cliquez sur l’aire de conception, puis sur activer un Modelbus.Right-click the design surface and then click Enable Modelbus. Dans la boîte de dialogue, choisissez l'une ou l'autre des options.In the dialog box, choose one or both of the options. Cliquez sur OK.Click OK. Un nouveau projet « ModelBus » vient s'ajouter à la solution DSL.A new project "ModelBus" is added to the DSL solution.

    3. Cliquez sur transformer tous les modèles et régénérez la solution.Click Transform All Templates and rebuild the solution.

Pour envoyer un objet à partir d’une source de DSLTo send an object from a source DSL

  1. Dans votre sous-classe ElementOperations, remplacez Copy() de telle sorte qu'elle encode une MBR (Model Bus Reference) en IDataObject.In your ElementOperations subclass, override Copy() so that it encodes a Model Bus Reference (MBR) into the IDataObject. Cette méthode est appelée quand l'utilisateur commence à exécuter un déplacement depuis le diagramme source.This method will be called when the user starts to drag from the source diagram. La MBR encodée est alors disponible dans l'IDataObject quand l'utilisateur dépose l'élément dans le diagramme cible.The encoded MBR will then be available in the IDataObject when the user drops in the target diagram.

    
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Modeling.Shell;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Integration;
    using Microsoft.VisualStudio.Modeling.Integration.Shell;
    using System.Drawing; // PointF
    using  System.Collections.Generic; // ICollection
    using System.Windows.Forms; // for IDataObject
    ...
    public class MyElementOperations : DesignSurfaceElementOperations
    {
        public override void Copy(System.Windows.Forms.IDataObject data, System.Collections.Generic.ICollection<ModelElement> elements, ClosureType closureType, System.Drawing.PointF sourcePosition)
        {
          base.Copy(data, elements, closureType, sourcePosition);
    
          // Get the ModelBus service:
          IModelBus modelBus =
              this.Store.GetService(typeof(SModelBus)) as IModelBus;
          DocData docData = ((VSDiagramView)this.Diagram.ActiveDiagramView).DocData;
          string modelFile = docData.FileName;
          // Get an adapterManager for the target DSL:
          ModelBusAdapterManager manager =
              (modelBus.FindAdapterManagers(modelFile).First());
          ModelBusReference modelReference = manager.CreateReference(modelFile);
          ModelBusReference elementReference = null;
          using (ModelBusAdapter adapter = modelBus.CreateAdapter(modelReference))
          {
            elementReference = adapter.GetElementReference(elements.First());
          }
    
          data.SetData("ModelBusReference", elementReference);
        }
    ...}
    

Pour recevoir une MBR à partir d'un DSL dans un projet DSL ou UML cibleTo receive a Model Bus Reference from a DSL in a target DSL or UML project

  1. Dans le projet DSL cible, ajoutez les références de projet aux projets suivants :In the target DSL project, add project references to:

    • Le projet DSL source.The source Dsl project.

    • Le projet ModelBus source.The source ModelBus project.

  2. Dans le fichier de code du gestionnaire de mouvements, ajoutez les références d'espaces de noms suivantes :In the gesture handler code file, add the following namespace references:

    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.Integration;
    using SourceDslNamespace;
    using SourceDslNamespace.ModelBusAdapters;
    
  3. L'exemple suivant illustre comment accéder à l'élément de modèle source :The following sample illustrates how to get access to the source model element:

    partial class MyTargetShape // or diagram or connector
    {
      internal void ProcessDragDropItem(DiagramDragEventArgs diagramDragEventArgs)
      {
        // Verify that we're being passed an Object Shape.
        ElementGroupPrototype prototype = diagramDragEventArgs.Prototype;
        if (prototype == null) return;
        if (Company.InstanceDiagrams.ObjectShape.DomainClassId
          != prototype.RootProtoElements.First().DomainClassId)
          return;
        // - This is an ObjectShape.
        // - We need to access the originating Store, find the shape, and get its object.
    
        IModelBus modelBus = targetDropElement.Store.GetService(typeof(SModelBus)) as IModelBus;
    
        // Unpack the MBR that was packed in Copy:
        ModelBusReference reference = diagramDragEventArgs.Data.GetData("ModelBusReference") as ModelBusReference;
        using (SourceDslAdapter adapter = modelBus.CreateAdapter(reference) as SourceDslAdapter)
        {
          using (ILinkedUndoTransaction t = LinkedUndoContext.BeginTransaction("doing things"))
          {
            // Quickest way to get the shape from the MBR:
            ObjectShape firstShape = adapter.ResolveElementReference<ObjectShape>(reference);
    
            // But actually there might be several shapes - so get them from the prototype instead:
            IElementDirectory remoteDirectory = adapter.Store.ElementDirectory;
            foreach (Guid shapeGuid in prototype.SourceRootElementIds)
            {
              PresentationElement pe = remoteDirectory.FindElement(shapeGuid) as PresentationElement;
              if (pe == null) continue;
              SourceElement instance = pe.ModelElement as SourceElement;
              if (instance == null) continue;
    
              // Do something with the object:
          instance...
            }
            t.Commit();
          }
        }
    }
    

Pour accepter un élément dont la source est un modèle UMLTo accept an element sourced from a UML model

  • L'exemple de code suivant accepte un objet déposé à partir d'un diagramme UML.The following code sample accepts an object dropped from a UML diagram.

    
      using Microsoft.VisualStudio.ArchitectureTools.Extensibility;
      using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
      using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
      using Microsoft.VisualStudio.Modeling;
      using Microsoft.VisualStudio.Modeling.Diagrams;
      using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
      using Microsoft.VisualStudio.Uml.Classes;
      using System;
      using System.ComponentModel.Composition;
      using System.Linq;
    ...
    partial class TargetShape
    {
      internal void ProcessDragDropItem(DiagramDragEventArgs diagramDragEventArgs)
      {
            EnvDTE.DTE dte = this.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
            // Find the UML project
            foreach (EnvDTE.Project project in dte.Solution.Projects)
            {
              IModelingProject modelingProject = project as IModelingProject;
              if (modelingProject == null) continue; // not a modeling project
              IModelStore store = modelingProject.Store;
              if (store == null) return;
    
              foreach (IDiagram dd in store.Diagrams())
              {
                  // Get Modeling.Diagram that implements UML.IDiagram:
                  Diagram diagram = dd.GetObject<Diagram>();
    
                  foreach (Guid elementId in e.Prototype.SourceRootElementIds)
                  {
                    ShapeElement shape = diagram.Partition.ElementDirectory.FindElement(elementId) as ShapeElement;
                    if (shape == null) continue;
                    // This example assumes the shape is a UML class:
                    IClass classElement = shape.ModelElement as IClass;
                    if (classElement == null) continue;
    
                    // Now do something with the UML class element ...
                  }
            }
          break; // don't try any more projects
    }  }  }
    

À l’aide des Actions de la souris : Faisant glisser des éléments de compartimentUsing Mouse Actions: Dragging Compartment Items

Vous pouvez écrire un gestionnaire qui intercepte les actions de la souris sur les champs d’une forme.You can write a handler that intercepts mouse actions on a shape's fields. L'exemple suivant permet à l'utilisateur de réordonner les éléments dans un compartiment en les faisant glisser avec la souris.The following example lets the user re-order the items in a compartment by dragging with the mouse.

Pour générer cet exemple, créez une solution à l’aide de la diagrammes de classes modèle de solution.To build this example, create a solution by using the Class Diagrams solution template. Ajoutez un fichier de code et ajoutez le code suivant.Add a code file and add the following code. Adaptez l'espace de noms pour qu'il soit identique au vôtre.Adjust the namespace to be the same as your own.

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Design;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Collections.Generic;
using System.Linq;

// This sample allows users to re-order items in a compartment shape by dragging.

// This example is built on the "Class Diagrams" solution template of VMSDK (DSL Tools).
// You will need to change the following domain class names to your own:
// ClassShape = a compartment shape
// ClassModelElement = the domain class displayed using a ClassShape
// This code assumes that the embedding relationships displayed in the compartments
// don't use inheritance (don't have base or derived domain relationships).

namespace Company.CompartmentDrag  // EDIT.
{
 /// <summary>
 /// Manage the mouse while dragging a compartment item.
 /// </summary>
 public class CompartmentDragMouseAction : MouseAction
 {
  private ModelElement sourceChild;
  private ClassShape sourceShape;
  private RectangleD sourceCompartmentBounds;

  public CompartmentDragMouseAction(ModelElement sourceChildElement, ClassShape sourceParentShape, RectangleD bounds)
   : base (sourceParentShape.Diagram)
  {
   sourceChild = sourceChildElement;
   sourceShape = sourceParentShape;
   sourceCompartmentBounds = bounds; // For cursor.
  }

  /// <summary>
  /// Call back to the source shape to drop the dragged item.
  /// </summary>
  /// <param name="e"></param>
  protected override void OnMouseUp(DiagramMouseEventArgs e)
  {
   base.OnMouseUp(e);
   sourceShape.DoMouseUp(sourceChild, e);
   this.Cancel(e.DiagramClientView);
   e.Handled = true;
  }

  /// <summary>
  /// Ideally, this shouldn't happen. This action should only be active
  /// while the mouse is still pressed. However, it can happen if you
  /// move the mouse rapidly out of the source shape, let go, and then
  /// click somewhere else in the source shape. Yuk.
  /// </summary>
  /// <param name="e"></param>
  protected override void OnMouseDown(DiagramMouseEventArgs e)
  {
   base.OnMouseDown(e);
   this.Cancel(e.DiagramClientView);
   e.Handled = false;
  }

  /// <summary>
  /// Display an appropriate cursor while the drag is in progress:
  /// Up-down arrow if we are inside the original compartment.
  /// No entry if we are elsewhere.
  /// </summary>
  /// <param name="currentCursor"></param>
  /// <param name="diagramClientView"></param>
  /// <param name="mousePosition"></param>
  /// <returns></returns>
  public override System.Windows.Forms.Cursor GetCursor(System.Windows.Forms.Cursor currentCursor, DiagramClientView diagramClientView, PointD mousePosition)
  {
   // If the cursor is inside the original compartment, show up-down cursor.
   return sourceCompartmentBounds.Contains(mousePosition)
    ? System.Windows.Forms.Cursors.SizeNS // Up-down arrow.
    : System.Windows.Forms.Cursors.No;
  }
 }

 /// <summary>
 /// Override some methods of the compartment shape.
 /// *** GenerateDoubleDerived must be set for this shape in DslDefinition.dsl. ****
 /// </summary>
 public partial class ClassShape
 {
  /// <summary>
  /// Model element that is being dragged.
  /// </summary>
  private static ClassModelElement dragStartElement = null;
  /// <summary>
  /// Absolute bounds of the compartment, used to set the cursor.
  /// </summary>
  private static RectangleD compartmentBounds;

  /// <summary>
  /// Attach mouse listeners to the compartments for the shape.
  /// This is called once per compartment shape.
  /// The base method creates the compartments for this shape.
  /// </summary>
  public override void EnsureCompartments()
  {
   base.EnsureCompartments();
   foreach (Compartment compartment in this.NestedChildShapes.OfType<Compartment>())
   {
    compartment.MouseDown += new DiagramMouseEventHandler(compartment_MouseDown);
    compartment.MouseUp += new DiagramMouseEventHandler(compartment_MouseUp);
    compartment.MouseMove += new DiagramMouseEventHandler(compartment_MouseMove);
   }
  }

  /// <summary>
  /// Remember which item the mouse was dragged from.
  /// We don't create an Action immediately, as this would inhibit the
  /// inline text editing feature. Instead, we just remember the details
  /// and will create an Action when/if the mouse moves off this list item.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseDown(object sender, DiagramMouseEventArgs e)
  {
   dragStartElement = e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault();
   compartmentBounds = e.HitDiagramItem.Shape.AbsoluteBoundingBox;
  }

  /// <summary>
  /// When the mouse moves away from the initial list item, but still inside the compartment,
  /// create an Action to supervise the cursor and handle subsequent mouse events.
  /// Transfer the details of the initial mouse position to the Action.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseMove(object sender, DiagramMouseEventArgs e)
  {
   if (dragStartElement != null)
   {
    if (dragStartElement != e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault())
    {
     e.DiagramClientView.ActiveMouseAction = new CompartmentDragMouseAction(dragStartElement, this, compartmentBounds);
     dragStartElement = null;
    }
   }
  }

  /// <summary>
  /// User has released the mouse button.
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void compartment_MouseUp(object sender, DiagramMouseEventArgs e)
  {
    dragStartElement = null;
  }

  /// <summary>
  /// Forget the source item if mouse up occurs outside the
  /// compartment.
  /// </summary>
  /// <param name="e"></param>
  public override void OnMouseUp(DiagramMouseEventArgs e)
  {
   base.OnMouseUp(e);
   dragStartElement = null;
  }

  /// <summary>
  /// Called by the Action when the user releases the mouse.
  /// If we are still on the same compartment but in a different list item,
  /// move the starting item to the position of the current one.
  /// </summary>
  /// <param name="dragFrom"></param>
  /// <param name="e"></param>
  public void DoMouseUp(ModelElement dragFrom, DiagramMouseEventArgs e)
  {
   // Original or "from" item:
   ClassModelElement dragFromElement = dragFrom as ClassModelElement;
   // Current or "to" item:
   ClassModelElement dragToElement = e.HitDiagramItem.RepresentedElements.OfType<ClassModelElement>().FirstOrDefault();
   if (dragFromElement != null && dragToElement != null)
   {
    // Find the common parent model element, and the relationship links:
    ElementLink parentToLink = GetEmbeddingLink(dragToElement);
    ElementLink parentFromLink = GetEmbeddingLink(dragFromElement);
    if (parentToLink != parentFromLink && parentFromLink != null && parentToLink != null)
    {
     // Get the static relationship and role (= end of relationship):
     DomainRelationshipInfo relationshipFrom = parentFromLink.GetDomainRelationship();
     DomainRoleInfo parentFromRole = relationshipFrom.DomainRoles[0];
     // Get the node in which the element is embedded, usually the element displayed in the shape:
     ModelElement parentFrom = parentFromLink.LinkedElements[0];

     // Same again for the target:
     DomainRelationshipInfo relationshipTo = parentToLink.GetDomainRelationship();
     DomainRoleInfo parentToRole = relationshipTo.DomainRoles[0];
     ModelElement parentTo = parentToLink.LinkedElements[0];

     // Mouse went down and up in same parent and same compartment:
     if (parentTo == parentFrom && relationshipTo == relationshipFrom)
     {
      // Find index of target position:
      int newIndex = 0;
      var elementLinks = parentToRole.GetElementLinks(parentTo);
      foreach (ElementLink link in elementLinks)
      {
       if (link == parentToLink) { break; }
       newIndex++;
      }

      if (newIndex < elementLinks.Count)
      {
       using (Transaction t = parentFrom.Store.TransactionManager.BeginTransaction("Move list item"))
       {
        parentFromLink.MoveToIndex(parentFromRole, newIndex);
        t.Commit();
       }
      }
     }
    }
   }
  }

  /// <summary>
  /// Get the embedding link to this element.
  /// Assumes there is no inheritance between embedding relationships.
  /// (If there is, you need to make sure you've got the relationship
  /// that is represented in the shape compartment.)
  /// </summary>
  /// <param name="child"></param>
  /// <returns></returns>
  ElementLink GetEmbeddingLink(ClassModelElement child)
  {
   foreach (DomainRoleInfo role in child.GetDomainClass().AllEmbeddedByDomainRoles)
   {
    foreach (ElementLink link in role.OppositeDomainRole.GetElementLinks(child))
    {
     // Just the assume the first embedding link is the only one.
     // Not a valid assumption if one relationship is derived from another.
     return link;
    }
   }
   return null;
  }
 }
}

Voir aussiSee Also

Note

Dans Visual Studio 2017, le SDK de Transformation de modèle de texte et le SDK de modélisation de Visual Studio sont installés automatiquement lorsque vous installez des fonctionnalités spécifiques de Visual Studio.In Visual Studio 2017, the Text Template Transformation SDK and the Visual Studio Modeling SDK are installed automatically when you install specific features of Visual Studio. Pour plus d’informations, consultez ce billet de blog.For more details, see this blog post.