Condividi tramite


Procedura: aggiungere un gestore di trascinamento della selezione

È possibile aggiungere i gestori per gli eventi di trascinamento della selezione a DSL, in modo che gli utenti possono trascinare gli elementi del diagramma da altri diagrammi o da altre parti di Visual Studio.È inoltre possibile aggiungere gestori per gli eventi come si fa doppio clic su.Insieme, il trascinamento della selezione e fare doppio clic sui gestori è noto come gestori movimenti.

In questo argomento vengono descritti i movimenti di trascinamento della selezione che hanno origine in altri diagrammi.Per gli eventi di copia e di spostamento all'interno di un unico diagramma, considerare l'alternativa di definizione della sottoclasse di ElementOperations.Per ulteriori informazioni, vedere Procedura: programmare il comportamento della funzione Copia e incolla (reindirizzamento).È inoltre possibile personalizzare la definizione DSL.

In questo argomento

  • Le prime due sezioni vengono descritti i metodi alternativi per definire un gestore movimenti:

    • Definizione di gestori movimenti eseguendo l'override dei metodi di ShapeElement.OnDragDrop, OnDoubleClick, OnDragOvere altri metodi possono essere sottoposti a override.

    • Definizione di gestori movimenti tramite MEF.Utilizzare questo metodo se si desidera che gli sviluppatori di terze parti per poter definire propri gestori al modello DSL.Gli utenti possono scegliere per installare le estensioni di terze parti dopo che ha installato il modello DSL.

  • come decodificare l'elemento trascinato.Gli elementi possono essere trascinati da qualsiasi finestra o dal desktop nonché da un modello DSL.

  • come ottenere l'elemento trascinato originale.Se l'elemento trascinato è un elemento DSL, è possibile aprire il modello di origine e accedere all'elemento.

  • Utilizzando le azioni del mouse: Trascinare gli elementi del raggruppamento.In questo esempio viene illustrato un gestore di livello inferiore che rileva le azioni del mouse sui campi di una forma.Nell'esempio l'utente riordinare gli elementi in un raggruppamento trascinandole con il mouse.

Definizione di gestori movimenti eseguendo l'override dei metodi di ShapeElement

Aggiungere un nuovo file di codice al progetto di modello DSL.Per un gestore movimenti, in genere è necessario avere almeno quanto segue using istruzioni:

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

Nel nuovo file, definire una classe parziale per la classe del diagramma o shape che dovrà rispondere all'operazione di trascinamento.Eseguire l'override dei metodi seguenti:

  • OnDragOver- Questo metodo viene chiamato quando il puntatore del mouse si sposta la forma durante un'operazione di trascinamento.Il metodo deve verificare l'elemento che l'utente sta trascinando e impostare la proprietà dell'effetto per indicare se l'utente possibile eliminare la voce nella forma.La proprietà dell'effetto determina l'aspetto del cursore quando è posizionato sulla forma e determina anche se OnDragDrop() verrà chiamato quando l'utente rilascia il pulsante del mouse.

    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 - Questo metodo viene chiamato se l'utente rilascia il pulsante del mouse mentre le modifiche del puntatore del mouse su questa forma o diagramma, se OnDragOver(DiagramDragEventArgs e) precedentemente impostata e.Effect su un valore diverso da 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 - Questo metodo viene chiamato quando l'utente fa doppio clic sulla forma o il diagramma.

    Per ulteriori informazioni, vedere Procedura: intercettare un clic su una forma o su un elemento Decorator.

definire IsAcceptableDropItem(e) per determinare se l'elemento trascinato è accettabile e ProcessDragDropItem (e) per aggiornare il modello quando l'elemento viene rilasciato.Questi metodi devono prima disegnare l'elemento dagli argomenti dell'evento.Per informazioni su come eseguire questa operazione, vedere Come ottenere un riferimento all'elemento trascinato.

Definizione di gestori movimenti tramite MEF

Il framework MEF (extensibility Framework) consente di definire i componenti che possono essere installate con una configurazione minima.Per ulteriori informazioni, vedere Managed Extensibility Framework (MEF).

Per definire un gestore movimenti MEF

  1. Aggiungere a Dsl e DslPackage i progetti MefExtension file che sono descritti in Estendere il DSL mediante MEF.

  2. È ora possibile definire un gestore movimenti come componente 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);
       }
    
    

    È possibile creare più di uno parte del gestore movimenti, ad esempio quando si dispone di diversi tipi di oggetti trascinati.

  3. Aggiungere le definizioni di classe parziale per le classi di destinazione della forma, del connettore o del diagramma e definire i metodi IsAcceptableDropItem() e ProcessDragDropItem().Questi metodi devono iniziare estraendo l'elemento trascinato dagli argomenti dell'evento.Per ulteriori informazioni, vedere Come ottenere un riferimento all'elemento trascinato.

come decodificare l'elemento trascinato

Quando l'utente trascina un elemento del diagramma, o da una parte del diagramma a un altro, le informazioni sull'elemento che sta trascinando sono disponibili in [DiagramDragEventArgs].Poiché l'operazione di trascinamento possibile iniziare a qualsiasi oggetto sullo schermo, i dati possono essere disponibili in uno dei diversi formati.Il codice deve riconoscere i formati con il quale è in grado di gestire.

Per individuare i formati in cui le informazioni di origine di trascinamento sono disponibili, eseguire il codice in modalità di debug, l'impostazione di un punto di interruzione alla voce con OnDragOver() o CanDragDrop().Controllare i valori di DiagramDragEventArgs parametro.Le informazioni vengono fornite in due formati:

  • IDataObjectData - Questa proprietà porta le versioni serializzate di oggetti di origine, in genere in più di un formato.Le funzioni più utili:

    • diagramma EventArgs.Data.GetDataFormats() - elencati i formati in cui è possibile decodificare l'oggetto trascinato.Ad esempio, se l'utente trascina un file dal desktop, i formati disponibili includono il nome file ("FileNameW").

    • diagramEventArgs.Data.GetData(format) - Decodifica l'oggetto trascinato nel formato specificato.Eseguire il cast dell'oggetto al tipo appropriato.Di seguito è riportato un esempio:

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

      È inoltre possibile trasmettere gli oggetti come riferimenti di template bus dal database di origine in per essere proprietario di formato personalizzato.Per ulteriori informazioni, vedere Come inviare i riferimenti di template bus in un trascinamento e in una destinazione.

  • ElementGroupPrototypePrototype - Utilizzare questa proprietà su se si desidera che gli utenti per trascinare gli elementi da un modello DSL o da un modello UML.Un prototipo del gruppo dell'elemento contiene uno o più oggetti, i collegamenti e i relativi valori della proprietà.Viene inoltre utilizzato nelle operazioni incollare e quando si aggiunge un elemento dalla casella degli strumenti.In un prototipo, gli oggetti e i relativi tipi vengono identificati dal GUID.Ad esempio, questo codice consente degli elementi della classe del trascinamento da un diagramma UML o da Esplora modelli UML di modello:

    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
    }
    

    Per accettare le forme UML, determinare i GUID delle classi di forma UML dall'esperimento.Tenere presente che esiste in genere più di un tipo di elemento in un diagramma.Si ricordi inoltre che un oggetto trascinato da un diagramma UML o DSL è la forma, non l'elemento del modello.

DiagramDragEventArgs presenta inoltre le proprietà che indicano la posizione corrente del puntatore del mouse e se l'utente sta premendo CTRL, ALT, o i tasti MAIUSC.

Come ottenere la versione originale di un elemento trascinato

Data e Prototype le proprietà degli argomenti contengono solo un riferimento alla forma trascinati.In generale, se si desidera creare un oggetto nel database di destinazione DSL derivato dal prototipo in qualche modo, è necessario ottenere l'accesso all'originale, ad esempio, leggendo il contenuto del file, o esplorante all'elemento del modello rappresentato da una forma.È possibile utilizzare model bus di modello di Visual Studio per facilitare questa operazione.

Per preparare un modello DSL progetto per modellare bus di modello

  • Rendere il database di origine DSL accessibile da Visual Studio bus di modello:

    1. Scaricare e installare l'estensione di bus del modello di Visual Studio, se non è già installata.Per ulteriori informazioni, vedere L'sdk di visualizzazione e modellazione.

    2. Aprire il file di definizione di IL database di origine DSL nella finestra di progettazione DSL.Fare clic con il pulsante destro del mouse sull'area di progettazione e scegliere abilitare Modelbus.Nella finestra di dialogo, selezionare una o entrambe le opzioni.Scegliere OK.Un nuovo progetto “ModelBus„ aggiunto alla soluzione DSL.

    3. Fare clic su Trasformazione di tutti i modelli e ricompilare la soluzione.

Per inviare un oggetto da un'origine DSL

  • Nella sottoclasse di ElementOperations, eseguire l'override Copy() affinché codifichi un riferimento di template bus (MBR) in IDataObject.Questo metodo verrà chiamato quando l'utente inizia a trascinare dal diagramma originale.Il MBR codificato sarà quindi disponibile in IDataObject quando le cadute dell'utente nel diagramma di destinazione.

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

Per ricevere un riferimento di template bus da un linguaggio specifico di dominio in un database di destinazione DSL o UML progetto

  1. Nel progetto di modello DSL del database di destinazione, aggiungere i riferimenti al progetto a:

    • Il progetto di Dsl di origine.

    • il progetto originale ModelBus.

  2. Nel file di codice del gestore movimenti, aggiungere i seguenti riferimenti agli spazi dei nomi:

    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. Nell'esempio seguente viene illustrato come accedere all'elemento del modello di origine:

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

Per accettare un elemento ha originato da un modello UML

  • Nell'esempio di codice accetta un oggetto rilasciato da un diagramma 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 
    }  }  }
    

Utilizzando le azioni del mouse: Trascinare gli elementi del raggruppamento

È possibile scrivere un gestore che rileva le azioni del mouse sui campi di una forma.L'esempio seguente consente di riordinare gli elementi in un raggruppamento trascinandole con il mouse.

Per compilare questo esempio, creare una soluzione tramite diagrammi classi modello della soluzione.Aggiungere un file di codice e aggiungere il codice seguente.Modificare lo spazio dei nomi per corrispondere a proprietari.

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

Vedere anche

Concetti

Personalizzazione del comportamento di copia

Procedura: programmare il comportamento della funzione Copia e incolla (reindirizzamento)