Partager via


Comment : ajouter un gestionnaire glisser-déplacer

Vous pouvez ajouter des gestionnaires pour les événements glisser-déplacer à votre DÉSOLÉ, afin que les utilisateurs puissent faire glisser des éléments vers un diagramme d'autres diagrammes ou d'autres parties de Visual Studio.Vous pouvez également ajouter des gestionnaires pour les événements tels que double-clique sur.Ensemble, le glisser-déplacer et les gestionnaires de double-clic sont appelées gestionnaires de mouvements.

Cette rubrique traite des entrées glisser-déplacer commençant par d'autres diagrammes.Pour les événements de déplacement et de copie dans un diagramme unique, considérez l'alternative de définir une sous-classe d' ElementOperations.Pour plus d'informations, consultez Comment : programmer le comportement de la commande copier-coller - redirection.Vous pouvez également pouvoir personnaliser la définition de langage spécifique à un domaine.

Dans cette rubrique

  • Les deux premières sections décrivent les autres méthodes pour définir un gestionnaire de mouvements :

    • Vous définissez des gestionnaires de mouvements en substituant les méthodes de ShapeElement.OnDragDrop, OnDoubleClick, OnDragOver, et d'autres méthodes peuvent être substitués.

    • Définir des gestionnaires de mouvements en utilisant MEF.Utilisez cette méthode si vous souhaitez les développeurs tiers pour pouvoir définir leurs propres gestionnaires à votre DÉSOLÉ.Les utilisateurs peuvent choisir d'installer des tiers extensions après avoir installé votre DÉSOLÉ.

  • Décodez de l'élément glissé.Les éléments peuvent être déplacés à partir de n'importe quelle fenêtre ou du Bureau, ainsi qu'un langage spécifique à un domaine.

  • Explique comment obtenir l'élément déplacé d'origine.Si l'élément glissé est un élément DÉSOLÉ, vous pouvez ouvrir le modèle de source et accéder à l'élément.

  • L'utilisation d'actions de souris : faire glisser des éléments de compartiment.Cet exemple montre un gestionnaire plus simple qui intercepte les actions de la souris sur les champs d'une forme.L'exemple permet à l'utilisateur retrier les éléments dans un compartiment par un glisser-déplacer.

Vous définissez des gestionnaires de mouvements en substituant les méthodes de ShapeElement

Ajoutez un nouveau fichier de code à votre projet DÉSOLÉ.Pour un gestionnaire de mouvements, vous devez généralement avoir au moins les instructions suivantes d' using :

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

Dans le nouveau fichier, définissez une classe partielle pour la classe de forme ou de diagramme qui doit répondre à l'opération glisser.substituez les méthodes suivantes :

  • OnDragOver- cette méthode est appelée lorsque le pointeur de la souris entre dans la forme pendant une opération glisser.Votre méthode doit obtenir l'élément que l'utilisateur fait glisser, et définir la propriété d'effet pour indiquer si l'utilisateur peut supprimer l'élément sur cette forme.La propriété d'effet détermine l'apparence du curseur pendant qu'elle est sur cette forme, et détermine également si OnDragDrop() est appelé lorsque l'utilisateur relâche le bouton de la souris.

    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 pendant que les absences de pointeur de la souris sur cette forme ou diagramme, si OnDragOver(DiagramDragEventArgs e) définit précédemment e.Effect une valeur autre qu' 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 diagramme.

    Pour plus d'informations, consultez Comment : intercepter un événement Click sur une forme ou un décorateur.

Définissez IsAcceptableDropItem(e) pour déterminer si l'élément glissé est acceptable, et ProcessDragDropItem (e) pour mettre à jour votre modèle lorsque l'élément est supprimé.ces méthodes doivent d'abord extraire l'élément des arguments d'événement.Pour plus d'informations sur la manière de procéder, consultez l' Explique comment obtenir une référence à l'élément glissé.

Définir des gestionnaires de mouvements en utilisant MEF

MEF (managed extensibility) vous permet de définir les composants qui peuvent être installés avec une configuration minime.Pour plus d'informations, consultez Managed Extensibility Framework (MEF).

Pour définir un gestionnaire de mouvements MEF

  1. Ajoutez à vos projets d' Dsl et d' DslPackage les fichiers d' MefExtension décrits dans Extension de votre DSL à l'aide de MEF.

  2. Vous pouvez maintenant définir un gestionnaire de mouvements en tant que composant MEF :

      // 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 composant de gestionnaire de mouvements, par exemple lorsque vous avez différents types d'objets déplacés.

  3. Ajoutez les définitions de classe partielles pour les classes cibles de forme, de connecteur ou de diagramme, puis définissez les méthodes IsAcceptableDropItem() et ProcessDragDropItem().Ces méthodes doivent commencer la récupération de l'élément fait glisser les arguments d'événement.Pour plus d'informations, consultez l' Explique comment obtenir une référence à l'élément glissé.

Décodez de l'élément glissé

Lorsque l'utilisateur fait glisser un élément sur votre diagramme, ou d'une partie de votre diagramme à un autre, les informations relatives à l'élément qui est déplacé sont disponibles dans [DiagramDragEventArgs].Étant donné que l'opération de glissement peut avoir commencé à tout objet à l'écran, les données peuvent être disponibles dans les de divers formats.Votre code doit identifier les formats avec lesquels il est capable de traitement.

Pour découvrir les formats dans lesquels vos informations de source de glissement sont disponibles, exécutez votre code en mode débogage, le paramètre un point d'arrêt à l'entrée à OnDragOver() ou l' CanDragDrop().inspectez les valeurs du paramètre d' DiagramDragEventArgs .Les informations sont fournies sous deux formes :

  • IDataObjectData - cette propriété contient les versions sérialisées des objets sources, généralement dans plusieurs format.ses fonctions plus utiles sont :

    • diagramme EventArgs.Data.GetDataFormats() - répertorie les formats dans lesquels vous pouvez décoder l'objet glissé.Par exemple, si l'utilisateur fait glisser un fichier du Bureau, les formats disponibles incluent le nom de fichier ("FileNameW").

    • diagramEventArgs.Data.GetData(format) - décode l'objet glissé dans le format spécifié.Castez l'objet en type approprié.Par exemple :

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

      vous pouvez également transmettre des objets tels que des références de modèle de bus de la source dans votre propre format personnalisé.Pour plus d'informations, consultez l' envoyez procédure les références de modèle de bus dans un glisser-déplacer.

  • ElementGroupPrototypePrototype - utilisez cette propriété pour permettre aux utilisateurs de faire glisser des éléments d'un DÉSOLÉ ou d'un modèle UML.Un prototype de groupe d'élément contient un ou plusieurs objets, des liens, et leurs valeurs de propriété.Il est également utilisé dans les opérations de coller et lorsque vous ajoutez un élément de la boîte à outils.Dans un prototype, les objets et leurs types sont identifiés par un GUID.Par exemple, ce code permet l'utilisateur aux éléments de classe de glisser-déplacer d'un diagramme UML ou de l'Explorateur de modèles UML :

    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 recevoir des formes UML, déterminez les GUID des classes de forme UML par expérience.N'oubliez pas qu'il existe habituellement plusieurs type d'élément sur un diagramme.Souvenez -vous également qu'un objet glissé d'un DÉSOLÉ ou d'un diagramme UML est la forme, et non l'élément de modèle.

DiagramDragEventArgs a également les propriétés indiquant la position actuelle du pointeur de la souris et si l'utilisateur appuie sur la touche CTRL enfoncée, ALT, ou la touche MAJ enfoncée.

Explique comment obtenir le d'origine d'un élément glissé

Les propriétés d' Data et d' Prototype des arguments d'événement contiennent uniquement une référence à la forme glissées.Généralement, si vous souhaitez créer un objet de la cible DÉSOLÉ dérivée du prototype de, vous devez obtenir l'accès à l'origine, par exemple, lisant le contenu du fichier, ou d'accéder à l'élément de modèle représenté par une forme.Vous pouvez utiliser le bus de modèle Visual Studio pour vous aider à ce.

Pour préparer un projet DÉSOLÉ pour le bus de modèle

  • Rendez la source DÉSOLÉ accessible par le bus de modèle de Visual Studio :

    1. Téléchargez et installez l'extension de mégabus de modèle Visual Studio, si ce n'est déjà installée.Pour plus d'informations, consultez Visualization and Modeling SDK.

    2. Ouvrez le fichier de définition DÉSOLÉ de la source DÉSOLÉ dans le concepteur de langage spécifique à un domaine.Cliquez avec le bouton droit sur l'aire de conception puis cliquez sur Vérifiez Modelbus.Dans la boîte de dialogue, choisissez une ou les deux options.Cliquez sur OK.Un nouveau projet « ModelBus » est ajouté à la solution DÉSOLÉ.

    3. cliquez sur Transformer tous les modèles et régénérez la solution.

Pour envoyer un objet à partir d'une source DÉSOLÉ

  • Dans votre sous-classe d'ElementOperations, substitution Copy() afin qu'il encode une référence de modèle de bus (MBR) dans l'IDataObject.Cette méthode est appelée lorsque l'utilisateur commence à faire glisser du diagramme source.Le MBR encodé sera ensuite disponible dans l'IDataObject lorsque l'utilisateur supprime du schéma cible.

    
    
    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 référence de modèle de bus d'un DÉSOLÉ dans une cible DÉSOLÉ ou le projet UML

  1. Dans le projet de la cible DÉSOLÉ, ajoutez les références de projet à :

    • Le projet de la source DÉSOLÉ.

    • Le projet ModelBus source.

  2. Dans le fichier de code du gestionnaire de mouvements, ajoutez des références d'espace de noms suivantes :

    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 montre comment obtenir l'accès à l'élément de modèle source :

      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 recevoir un élément a alimenté d'un modèle UML

  • L'exemple de code suivant accepte un objet supprimé d'un diagramme UML.

      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'utilisation d'actions de souris : faire glisser des éléments de compartiment

Vous pouvez écrire un gestionnaire qui intercepte les actions de la souris sur les champs d'une forme.L'exemple suivant permet à l'utilisateur retrier les éléments dans un compartiment par un glisser-déplacer.

Pour générer cet exemple, créez une solution à l'aide de le modèle de solution de diagrammes de classes .Ajoutez un fichier de code et ajoutez le code suivant.Modifiez l'espace de noms soient les mêmes que le vôtre.

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 aussi

Concepts

Personnalisation du comportement de la commande copier

Comment : programmer le comportement de la commande copier-coller - redirection