Udostępnij za pośrednictwem


Jak: Dodawanie obsługi przeciągania i upuszczania

Programy obsługi zdarzeń przeciągnij i upuść można dodać do linii DSL, tak, aby użytkownicy można przeciągać elementy diagramu z innych diagramach lub innych części Visual Studio.Można również dodać obsługi dla zdarzenia takie jak klika dwukrotnie.Razem, przeciągania i upuszczania, a następnie dwukrotnie kliknij programy obsługi są znane jako obsługi w przypadku gestu odpowiadającego.

W tym temacie omówiono gesty przeciągania i upuszczania, które pochodzą w innych diagramach.Dla zdarzeń przenoszenia i kopiowania w obrębie jednego diagramu, należy wziąć pod uwagę alternatywnej definiowanie podklasy z ElementOperations.Aby uzyskać więcej informacji, zobacz Jak: kopia programu i zachowanie Wklej - przekierowania.Można również dostosować definicję DSL.

W tym temacie

  • Pierwsze dwie sekcje opisują alternatywne metody definiowania Obsługa gestu:

    • Definiowanie obsługi gestu metodami przesłanianie ShapeElement.OnDragDrop, OnDoubleClick, OnDragOver, i innych metod może zostać zastąpiona.

    • Definiowanie obsługi gestu przy użyciu MEF.Tej metody należy użyć, jeśli chcesz niezależnych producentów, aby móc zdefiniować własne programy obsługi do linii DSL.Użytkownicy mogą wybrać zainstalować rozszerzenia strony trzeciej, po zainstalowany modem DSL.

  • Sposób dekodowania przeciągany element.Elementy można przeciągać z dowolnego okna lub z pulpitu, jak również z modemu DSL.

  • Jak uzyskać oryginału przeciągnięty element.Jeśli przeciągany element jest elementem DSL, można otworzyć modelu źródłowego i dostęp do elementu.

  • Za pomocą akcji myszy: Przeciąganie elementów przedziału.W przykładzie pokazano obsługi niższego poziomu, który przechwytuje działania myszy na polach kształtu.Przykład pozwala uporządkować elementy w przedziale, przeciągając myszą.

Definiowanie obsługi gestu poprzez zastąpienie metody ShapeElement

Dodawanie nowego pliku kodu do projektu DSL.Obsługa gestu, zazwyczaj mają co najmniej następujące using instrukcji:

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

W nowym pliku należy zdefiniować częściowej klasy dla klasy kształtu lub diagram, które powinny odpowiedzieć na operacji przeciągania.Zastąpić następujące metody:

  • OnDragOver-Ta metoda jest wywoływane, gdy wskaźnik myszy zostanie umieszczony kształt podczas operacji przeciągania.Metodę należy sprawdzić element, który użytkownik jest przeciąganie i ustawić właściwość efekt, aby wskazać, czy użytkownik można upuścić element tego kształtu.Właściwość efekt określa wygląd kursora podczas znajduje się nad ten kształt, a także określa czy OnDragDrop() zostanie wywołana, gdy użytkownik zwolni przycisk myszy.

    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— Ta metoda jest wywoływana, gdy użytkownik zwolni przycisk myszy podczas, gdy wskaźnik myszy zatrzyma się nad ten kształt lub diagramu, jeśli OnDragOver(DiagramDragEventArgs e) ustawione wcześniej e.Effect na wartość inną niż 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— Ta metoda jest wywoływane, gdy użytkownik kliknie dwukrotnie kształt lub diagramu.

    Aby uzyskać więcej informacji, zobacz Jak: Przechwytywanie kliknij kształt lub Dekorator.

Definiowanie IsAcceptableDropItem(e) do określenia, czy dopuszczalne jest przeciągany element i ProcessDragDropItem(e) aktualizacji modelu po upuszczeniu elementu.Te metody, należy najpierw rozpakować element z argumentów zdarzeń.Aby uzyskać informacje na temat to zrobić, zobacz sposób uzyskać odwołanie do przeciągany element.

Definiowanie obsługi gestu przy użyciu MEF

MEF (Struktura rozszerzalności zarządzane) pozwala zdefiniować składniki, które można zainstalować z wymaga to minimalnej konfiguracji.Aby uzyskać więcej informacji, zobacz Oprogramowanie Managed Extensibility Framework (MEF).

Aby zdefiniować Obsługa gestu MEF

  1. Dodać do programu Dsl i DslPackage projektów MefExtension pliki, które są opisane w Przedłużenie linii DSL za pomocą MEF.

  2. Obsługa gestu teraz można zdefiniować jako składnik 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);
       }
    
    

    Można utworzyć więcej niż jeden składnik obsługi gest, na przykład gdy mają różne typy obiektów przeciąganych.

  3. Dodawanie definicji częściowej klasy dla kształtu docelowego, łącznika lub diagramów klas i definiować metody IsAcceptableDropItem() i ProcessDragDropItem().Te metody należy zacząć od wyodrębnianie przeciągany element z argumentów zdarzeń.Aby uzyskać więcej informacji, zobacz sposób uzyskać odwołanie do przeciągany element.

Sposób dekodowania przeciągany element

Gdy użytkownik przeciągnie element na diagramie, lub z jednej części diagramu na inny, informacje o elemencie, który jest przeciągane jest dostępny w [DiagramDragEventArgs].Ponieważ operacji przeciągania może mieć uruchomiony na dowolny obiekt na ekranie, dane mogą być dostępne w jednym z wielu różnych formatach.Kod musi rozpoznawać formaty, które jest zdolne do postępowania.

Odkryj formaty, w których przeciągnij źródło informacji jest dostępne, należy uruchomić w trybie Ustawianie punktu przerwania na wejściu do debugowania kodu OnDragOver() lub CanDragDrop().Sprawdź wartości DiagramDragEventArgs parametru.Informacje są dostarczane w dwóch formach:

  • IDataObject Data— Ta właściwość zwykle prowadzi szeregowany wersje obiektów źródła w więcej niż jeden format.Jego najbardziej przydatne funkcje są:

    • diagramEventArgs.Data.GetDataFormats() — Wyświetla listę formatów, w których można dekodować przeciągany obiekt.Na przykład, jeśli użytkownik przeciągnie pliku z pulpitu, dostępne formaty obejmują nazwę pliku ("FileNameW").

    • diagramEventArgs.Data.GetData(format)– Dekoduje przeciągany obiekt w określonym formacie.Rzutować obiekt do odpowiedniego typu.Na przykład:

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

      Obiekty takie jak model bus odwołania od źródła można również przekazywać w format niestandardowy.Aby uzyskać więcej informacji, zobacz sposób wysyłania Model Bus odniesienia w przeciągania i upuszczania.

  • ElementGroupPrototypePrototype– Użyć tej właściwości, jeśli użytkownicy mają przeciągnij elementy z modemu DSL lub modelu UML.Prototyp grupy element zawiera jeden lub więcej obiektów, łącza i ich wartości właściwości.Również służy w operacji wklejania i gdy dodajesz element z przybornika.W prototyp obiektów i ich typy są identyfikowane przez identyfikator Guid.Na przykład kod ten pozwala użytkownikowi przeciągnij elementy klasy z diagramu UML lub w Eksploratorze modelu 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
    }
    

    Aby zaakceptować kształty UML, ustalenie identyfikatorów GUID klas kształtu UML.Należy pamiętać, że jest zwykle więcej niż jeden typ elementu na dowolnym diagramie.Ponadto należy pamiętać, że obiekt przeciągany z diagramu DSL lub UML jest kształtu, a nie elementem modelu.

DiagramDragEventArgsma również właściwości, które wskazują bieżące położenie wskaźnika myszy i od tego, czy użytkownik jest naciśnięcie klawisza CTRL, ALT lub klawisze SHIFT.

Jak uzyskać oryginału przeciągany element

Data i Prototype właściwości argumentów zdarzeń zawierają tylko odwołanie do przeciągany kształt.Zwykle Jeśli chcesz utworzyć obiekt w docelowej DSL, która wywodzi się od prototypu w jakiś sposób jest potrzebny do uzyskania dostępu do oryginału, na przykład odczytu zawartości pliku lub przechodząc do elementu modelu reprezentowany przez kształt.Można użyć programu Visual Studio Model Bus, w tym pomóc.

Do przygotowania projektu DSL Model Bus

  • Udostępnić źródła DSL przez Visual Studio Model Bus:

    1. Pobierz i zainstaluj rozszerzenie programu Visual Studio Model Bus, jeśli nie jest zainstalowany.Aby uzyskać więcej informacji, zobacz wizualizacji i modelowania SDK.

    2. Otwórz plik definicji DSL źródła DSL w projektancie DSL.Kliknij prawym przyciskiem myszy na powierzchnię projektu, a następnie kliknij przycisk Włączyć Modelbus.W oknie dialogowym wybierz jedną lub obie opcje.Click OK.Nowy projekt "ModelBus" dodaje się do roztworu DSL.

    3. Kliknij przycisk Transform wszystkie szablony i przebudować roztworu.

Aby przesunąć obiekt o źródła DSL

  • W podklasie ElementOperations, należy zastąpić Copy() tak, aby go koduje odniesienia magistrali modelu (MBR) na IDataObject.Ta metoda będzie wywoływana, gdy użytkownik uruchamia przeciągnij z diagram Yródłowy.Zakodowany MBR będą wówczas dostępne w IDataObject, gdy użytkownik porzuca w docelowym diagramie.

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

Do otrzymywania odniesienia magistrali modelu z DSL w projekcie docelowym DSL lub UML

  1. Dodać odwołania projektu do projektu DSL docelowego:

    • Źródło projektu Dsl.

    • Źródło projektu ModelBus.

  2. W pliku kod obsługi gestu należy dodać następujące odwołania do nazw:

    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. Poniższy przykład ilustruje sposób uzyskać dostęp do elementu modelu źródłowego:

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

Aby zaakceptować element pochodzących z modelu UML

  • Poniższy przykładowy kod akceptuje obiekt usunięty z diagramu 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 
    }  }  }
    

Za pomocą akcji myszy: Przeciąganie elementów przedziału

Można napisać program obsługi, który przechwytuje działania myszy na polach kształtu.Poniższy przykład pozwala uporządkować elementy w przedziale, przeciągając myszą.

Budowanie w tym przykładzie, należy utworzyć za pomocą roztworu Diagramy klas roztwór szablonu.Dodawanie pliku kodu i Dodaj następujący kod.Dopasuj obszar nazw, być taka sama, jak własne.

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

Zobacz też

Koncepcje

Dostosowywanie zachowania kopii

Jak: kopia programu i zachowanie Wklej - przekierowania