Freigeben über


Gewusst wie: Hinzufügen eines Drag & Drop-Handlers

Sie können Handler für Drag & Drop-Ereignisse dem DSL hinzufügen, sodass Benutzer Elemente in das Diagramm aus anderen Diagrammen oder anderen Teilen von Visual Studioziehen können.Sie können Handler für Ereignisse wie Doppelklicke hinzufügen.Zusammen bekannte Drag & Drop, und doppelklicken Sie auf Klassenhandler als Gestenhandler.

Dieses Thema behandelt Drag & Drop-Gesten, die in anderen Diagrammen stammen.Für Verschiebungs- und Kopien von Ereignissen innerhalb eines einzelnen Diagramms zoomen, sollten Sie die Definition des alternativen einer Unterklasse von ElementOperations.Weitere Informationen finden Sie unter Gewusst wie: Programmieren von Kopier- und Einfügeverhalten - umleiten.Sie können auch die DSL-Definition anzupassen.

In diesem Thema

  • Die ersten beiden Abschnitten werden alternative Möglichkeiten zum Definieren eines Gestenhandlers:

    • Gestenhandler durch Überschreiben von ShapeElement-Methoden definieren.OnDragDrop, OnDoubleClick, OnDragOverund andere Methoden überschrieben werden können.

    • Gestenhandler mithilfe von MEF definieren.Verwenden Sie diese Methode, wenn Sie von Drittanbietern Entwickler in der Lage sein sollen, ihre eigenen Handler dem DSL zu definieren.Benutzer können die Erweiterungen von Drittanbietern zu installieren, nachdem sie das DSL installiert haben.

  • So erstellen Sie das gezogene Element decodiert.Elemente können von jedem Fenster oder dem Desktop als auch von einem DSL gezogen werden.

  • So erstellen Sie die Vorlage gezogene Element abruft.Wenn das gezogene Element ein DSL-Element ist, können Sie das Quellmodell öffnen und auf das Element zugreifen.

  • Verwenden von Maus-Aktionen: Ziehen Depot-Elemente.Dieses Beispiel zeigt einen Handler auf niedrigerer Ebene der Mausaktionen in den Feldern einer Form abfängt.Das Beispiel kann der Benutzer die Elemente in einem Depot neu anordnen, indem Sie mit der Maus gezogen hat.

Gestenhandler durch Überschreiben von ShapeElement-Methoden definieren

Fügen Sie dem DSL-Projekt eine neue Codedatei hinzu.Einen Gestenhandlers müssen Sie die folgenden Anweisungen using i. d. R. mindestens enthalten:

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

In der neuen Datei definieren Sie eine partielle Klasse für die Forms- oder Diagramm Klasse, die auf den Ziehvorgang reagieren soll.Überschreiben Sie die folgenden Methoden:

  • OnDragOver:Diese Methode wird aufgerufen, wenn der Mauszeiger die Form während eines Ziehvorgangs eintritt.Die Methode muss das Element überprüfen, die der Benutzer zieht, und die Auswirkungen der Eigenschaft festlegen, um anzugeben, ob der Benutzer das Element in dieser Form ablegen kann.Die Auswirkungen auf die Darstellung des Cursors Eigenschaft bestimmt, wie sie zu dieser Form ist, und bestimmt auch, ob OnDragDrop() wenn der Benutzer die Maustaste loslässt aufgerufen wird.

    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 :Diese Methode wird ein, wenn der Benutzer die Maustaste loslässt, während sich der Mauszeiger über diesem rest oder im Diagramm aufgerufen, wenn OnDragOver(DiagramDragEventArgs e)e.Effect zuvor auf einen anderen Wert als Nonefest.

    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 :Diese Methode wird aufgerufen, wenn der Benutzer die Form oder doppelklicken Sie auf das Diagramm.

    Weitere Informationen finden Sie unter Gewusst wie: Abfangen eines Klicks auf eine Form oder einen Decorator.

Definieren Sie IsAcceptableDropItem(e) , um zu bestimmen, ob das gezogene Element zulässig ist, und ProcessDragDropItem (e) das Modell aktualisieren, wenn das Element abgelegt wird.Diese Methoden müssen das Element von Ereignisargumenten zuerst extrahieren.Informationen darüber, wie Sie das finden Sie unter So erstellen Sie einen Verweis auf die gezogenen Elements abruftausführt.

Gestenhandler mithilfe von MEF definieren

Managed Extensibility Framework (MEF) können Sie Komponenten definieren, die mit minimaler Konfiguration installiert werden können.Weitere Informationen finden Sie unter Managed Extensibility Framework (MEF).

So definieren Sie einen MEF-Gestenhandler

  1. Fügen Sie Dsl hinzu, und DslPackage projiziert die MefExtension Dateien, die in Erweitern von DSL mittels MEFbeschrieben werden.

  2. Sie können jetzt als MEF-Komponente Definieren eines Gestenhandlers:

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

    Sie können mehr als eine Komponente für Gestenhandler erstellen, z. B., wenn Sie unterschiedliche Typen von gezogenen Objekten enthalten.

  3. Fügen Sie eine partielle Klassendefinitionen für das Ziel Form, den Konnektor oder die Klassen Diagramm hinzu, und definieren Sie die Methoden IsAcceptableDropItem() und ProcessDragDropItem().Diese Methoden müssen starten, indem sie das gezogene Element von Ereignisargumenten extrahieren.Weitere Informationen finden Sie unter So erstellen Sie einen Verweis auf die gezogenen Elements abruft.

So erstellen Sie das gezogene Element decodiert

Wenn der Benutzer ein Element im Diagramm oder einem Teil des Diagramms zu anderen zieht, werden Informationen zu dem Element, das gezogen wird, in [DiagramDragEventArgs]verfügbar.Da der Ziehvorgang an jedes Objekt auf dem Bildschirm möglicherweise begonnen haben, können die Daten entweder in einer Vielzahl von Formaten verfügbar sein.Der Code muss die Stile erkennen, mit denen er zum Behandeln der Lage ist.

Um die Stile zu ermitteln Ziehquellen in denen die Informationen verfügbar sind, führen Sie den Code im Debugmodus aus, und einen Haltepunkt am Eintrag OnDragOver() oder CanDragDrop()festlegen.Überprüfen Sie die Werte des DiagramDragEventArgs-Parameters.Die Informationen werden in zwei Formen enthalten:

  • IDataObjectData :Diese Eigenschaft enthält serialisierte Versionen der Quellobjekte, normalerweise in mehreren Formaten.Die nützlichsten Funktionen sind:

    • Diagramm EventArgs.Data.GetDataFormats() – Listet die Formate, in denen das gezogene Objekt decodieren können.Wenn der Benutzer beispielsweise eine Datei auf dem Desktop zieht, enthalten die verfügbaren FormateFileNameWden Dateinamen („") eingeschlossen werden.

    • diagramEventArgs.Data.GetData(format) – decodiert das gezogene Objekt im angegebenen Format.Wandelt das Objekt in den entsprechenden Typ um.Beispiele:

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

      Sie können Objekte Model Bus als Verweise auch in der Quelle übertragen, benutzerdefiniertes Format besitzen.Weitere Informationen finden Sie unter Verwenden von Bus-Verweise in einem Drag & Drop-Vorgang sendet.

  • ElementGroupPrototypePrototype – Verwenden Sie diese Eigenschaft, wenn Sie Benutzer Elemente aus einem DSL oder aus einem UML-Modell ziehen möchten.Ein prototyp Elementgruppen enthält ein oder mehrere Objekte, Links und ihre Eigenschaftswerte.Es wird auch in den Einfügevorgängen verwendet, und wenn Sie ein Element aus der Toolbox hinzufügen.In einem Prototyp werden Objekte und ihrer Typen durch GUID identifiziert.Beispielsweise ermöglicht dieser Code den Benutzer zu den Klassen Ziehen Sie Elemente aus einem UML-Diagramm oder UML-Modell-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
    }
    

    Um UML-Formen anzunehmen, sollten Sie die GUID der UML-Form Experiment von Klassen.Denken Sie daran, dass es normalerweise mehr als einen Typ von Element in jedem Diagramm vorhanden ist.Beachten Sie außerdem, dass ein Objekt, das von einem DSL- oder UML-Diagramm gezogen wird, der Form und nicht des Modellelements dabei.

DiagramDragEventArgs verfügt auch über Eigenschaften, die die aktuelle Position des Mauszeigers angeben und ob der Benutzer die UMSCHALTTASTE oder STRG, ALT gedrückt wird.

So erstellen Sie die Vorlage eines gegezogenen Elements abruft

Die Data und Prototype-Eigenschaften der Ereignisargumente enthalten nur einen Verweis auf die gezogenen Form.Normalerweise wenn Sie ein Objekt im Ziel DSL erstellen möchten, das aus dem Prototyp auf eine Weise abgeleitet ist, müssen Sie z. B. Lesen Sie den Zugriff auf die Vorlage den Inhalt der Datei navigieren oder mit dem Modellelement, das von einer Form dargestellt wird.Sie können Visual Studio-vorbildlichen Bus verwenden, um diesen zu unterstützen.

So fügen Sie ein Modell für DSL-Projekt Bus vorbereiten

  • Legen Sie die Quelle von Visual Studio Modell-Bus DSL zugegriffen werden:

    1. Herunterladen und Installieren Sie die Visual Studio-Modell-Buserweiterung, falls sie nicht bereits installiert ist.Weitere Informationen finden Sie unter Visualization and Modeling SDKunter.

    2. Öffnen Sie die Datei DSL-Definitions DSL-Designer in DSL der Quelle.Klicken Sie mit der rechten Maustaste auf die Entwurfsoberfläche, und klicken Sie dann auf ModelBus aktivieren.Wählen Sie im Dialogfeld eine oder beide Optionen aus.Klicken Sie auf OK.Ein neues Projekt „ModelBus“ wird zur DSL-Projektmappe hinzugefügt.

    3. Klicken Sie auf Alle Vorlagen transformieren und erstellen Sie die Projektmappe neu.

So fügen Sie ein Objekt aus einer Quelle übertragen DSL

  • In der ElementOperations-Unterklasse Überschreibung Copy() , sodass sie einem Modell Bus-Verweis (MBR) in das IDataObject codiert.Diese Methode wird vom beginnt, wenn der Benutzer Diagramm Quelle ziehen.Die codierte MBR ist dann im IDataObject wenn der Benutzer ablagen im Zieldiagramm verfügbar.

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

Um ein Modell aus einem Bus-Verweis DSL in einem Ziel empfangen UML-Projekt IN oder DSL

  1. Im Projekt des Ziels DSL fügen Sie Projektverweise hinzu:

    • Das Sources dsl-Projekt.

    • Das Quell-ModelBus-Projekt.

  2. Fügen Sie in der Codedatei für Gestenhandler die folgenden Namespaceverweise hinzu:

    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. Im folgenden Beispiel wird veranschaulicht, wie der Zugriff auf den modellelement Quelle abgerufen wird:

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

Um ein Element zu übernehmen, das von einem UML Model Sie Ursprungs ist

  • Im folgenden Codebeispiel nimmt ein Objekt, das von einem UML-Diagramm abgelegt wird.

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

Verwenden von Maus-Aktionen: Ziehen Depot-Elemente

Sie können einen Handler schreiben, der Mausaktionen in den Feldern einer Form abfängt.Im folgenden Beispiel kann der Benutzer die Elemente in einem Depot neu anordnen, indem Sie mit der Maus gezogen hat.

Um dieses Beispiel zu erstellen, erstellen Sie eine Projektmappe, indem Sie die Vorlage Klassendiagramme Projektmappen verwenden.Fügen Sie eine Codedatei hinzu, und fügen Sie den folgenden Code hinzu.Passen Sie die Namespace-, um dieselben wie der besitzen.

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

Siehe auch

Konzepte

Anpassen des Kopierverhaltens

Gewusst wie: Programmieren von Kopier- und Einfügeverhalten - umleiten