Dodawanie obsługi przeciągania i upuszczania

Można dodawać programy obsługi zdarzeń przeciągania i upuszczania do rozszerzenia DSL, aby użytkownicy mogli przeciągać elementy na diagram z innych diagramów lub z innych części programu Visual Studio. Można również dodać programy obsługi dla zdarzeń, takich jak dwukrotne kliknięcia. Razem programy obsługi przeciągania i upuszczania i dwukrotnego kliknięcia są nazywane procedurami obsługi gestów.

W tym temacie omówiono gesty przeciągania i upuszczania pochodzące z innych diagramów. W przypadku zdarzeń przenoszenia i kopiowania w ramach jednego diagramu rozważ alternatywę definiowania podklasy klasy ElementOperations. Aby uzyskać więcej informacji, zobacz Dostosowywanie zachowania kopiowania. Możesz również dostosować definicję DSL.

Definiowanie procedur obsługi gestów przez zastępowanie metod ShapeElement

OnDragDropMetody , OnDoubleClick, OnDragOveri inne można zastąpić.

Dodaj nowy plik kodu do projektu DSL. W przypadku obsługi gestów zwykle muszą istnieć co najmniej następujące using dyrektywy:

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

W nowym pliku zdefiniuj klasę częściową dla klasy kształtu lub diagramu, która powinna odpowiadać na operację przeciągania. Zastąpi następujące metody:

  • OnDragOver- Ta metoda jest wywoływana, gdy wskaźnik myszy wprowadza kształt podczas operacji przeciągania. Metoda powinna sprawdzić element, który użytkownik przeciąga, i ustawić właściwość Effect, aby wskazać, czy użytkownik może usunąć element na tym kształcie. Właściwość Effect określa wygląd kursora, gdy znajduje się nad tym kształtem, a także określa, czy OnDragDrop() będzie wywoływany, 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, jeśli użytkownik zwalnia przycisk myszy, gdy wskaźnik myszy spoczywa na tym kształcie lub diagramie, jeśli OnDragOver(DiagramDragEventArgs e) wcześniej ustawiono e.Effect 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ływana, gdy użytkownik kliknie dwukrotnie kształt lub diagram.

    Aby uzyskać więcej informacji, zobacz How to: Intercept a Click on a Shape or Decorator (Jak przechwytywać kliknięcie kształtu lub dekoratora).

Zdefiniuj IsAcceptableDropItem(e) , aby określić, czy przeciągnięty element jest akceptowalny, oraz ProcessDragDropItem(e) w celu zaktualizowania modelu po usunięciu elementu. Te metody muszą najpierw wyodrębnić element z argumentów zdarzeń. Aby uzyskać informacje o tym, jak to zrobić, zobacz Jak uzyskać odwołanie do przeciągniętego elementu.

Definiowanie procedur obsługi gestów przy użyciu interfejsu MEF

Użyj tej metody, jeśli chcesz, aby deweloperzy innych firm mogli definiować własne programy obsługi w języku DSL. Użytkownicy mogą zdecydować się na zainstalowanie rozszerzeń innych firm po zainstalowaniu rozszerzenia DSL.

Narzędzie MEF (Managed Extensibility Framework) umożliwia definiowanie składników, które można zainstalować przy użyciu minimalnej konfiguracji. Aby uzyskać więcej informacji, zobacz Managed Extensibility Framework (MEF).

Aby zdefiniować procedurę obsługi gestów MEF

  1. Dodaj do projektów Dsl i DslPackage pliki MefExtension opisane w temacie Rozszerzanie dsl przy użyciu mef.

  2. Teraz można zdefiniować procedurę obsługi gestów 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ów, taki jak w przypadku różnych typów przeciągniętych obiektów.

  3. Dodaj definicje klas częściowych dla kształtu docelowego, łącznika lub klas diagramu oraz zdefiniuj metody IsAcceptableDropItem() i ProcessDragDropItem(). Metody te muszą zaczynać się od wyodrębnienia przeciąganego elementu z argumentów zdarzeń. Aby uzyskać więcej informacji, zobacz Jak uzyskać odwołanie do przeciąganego elementu.

Jak zdekodować przeciągnięty element

Elementy można przeciągać z dowolnego okna lub z pulpitu, a także z rozszerzenia DSL.

Gdy użytkownik przeciąga element na diagram lub z jednej części diagramu do innej, informacje o przeciąganym elemencie są dostępne w elemencie DiagramDragEventArgs. Ponieważ operacja przeciągania mogła rozpocząć się w dowolnym obiekcie na ekranie, dane mogą być dostępne w dowolnym z różnych formatów. Kod musi rozpoznawać formaty, za pomocą których może on obsługiwać.

Aby odnaleźć formaty, w których są dostępne informacje o źródle przeciągania, uruchom kod w trybie debugowania, ustawiając punkt przerwania we wpisie na OnDragOver() lub CanDragDrop(). Sprawdź wartości parametru DiagramDragEventArgs . Informacje są udostępniane w dwóch formach:

  • IDataObjectData — Ta właściwość zawiera serializowane wersje obiektów źródłowych, zwykle w więcej niż jednym formacie. Najbardziej przydatne są następujące funkcje:

    • diagramEventArgs.Data.GetDataFormats() — wyświetla formaty, w których można zdekodować przeciągnięty obiekt. Jeśli na przykład użytkownik przeciągnie plik z pulpitu, dostępne formaty zawierają nazwę pliku ("FileNameW").

    • diagramEventArgs.Data.GetData(format) - Dekoduje przeciągnięty obiekt w określonym formacie. Rzutuj obiekt na odpowiedni typ. Na przykład:

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

      Można również przesyłać obiekty, takie jak odwołania do magistrali modelu ze źródła we własnym formacie niestandardowym. Aby uzyskać więcej informacji, zobacz How to Send Model Bus References in a Drag and Drop (Jak wysyłać odwołania do magistrali modelu w przeciąganiu i upuszczaniu).

  • ElementGroupPrototypePrototype — Użyj tej właściwości, jeśli chcesz, aby użytkownicy przeciągali elementy z modelu DSL lub UML. Prototyp grupy elementów zawiera co najmniej jeden obiekt, łącza i ich wartości właściwości. Jest on również używany w operacjach wklejania i podczas dodawania elementu z przybornika. W prototypie obiekty i ich typy są identyfikowane przez identyfikator GUID. Na przykład ten kod umożliwia użytkownikowi przeciąganie elementów klasy z diagramu UML lub Eksploratora modeli 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, określ identyfikatory GUID klas kształtów UML według eksperymentu. Należy pamiętać, że na dowolnym diagramie występuje zwykle więcej niż jeden typ elementu. Pamiętaj również, że obiekt przeciągnięty z diagramu DSL lub UML jest kształtem, a nie elementem modelu.

DiagramDragEventArgs Ma również właściwości wskazujące bieżącą pozycję wskaźnika myszy oraz to, czy użytkownik naciska klawisze CTRL, ALT lub SHIFT.

Jak uzyskać oryginał przeciąganego elementu

Jeśli przeciągnięty element jest elementem DSL, możesz otworzyć model źródłowy i uzyskać dostęp do elementu.

Właściwości Data i Prototype argumentów zdarzenia zawierają tylko odwołanie do przeciąganego kształtu. Zazwyczaj, jeśli chcesz utworzyć obiekt w docelowej wersji DSL pochodzącej z prototypu w jakiś sposób, musisz uzyskać dostęp do oryginału, na przykład odczytywać zawartość pliku lub przechodzić do elementu modelu reprezentowanego przez kształt. Aby uzyskać pomoc, możesz użyć magistrali modelu programu Visual Studio.

Aby przygotować projekt DSL dla usługi Model Bus

Udostępnij źródłową platformę DSL za pomocą magistrali modelu programu Visual Studio:

  1. Otwórz plik definicji DSL źródłowego rozszerzenia DSL w Projektant DSL. Kliknij prawym przyciskiem myszy powierzchnię projektową, a następnie kliknij pozycję Włącz modelbus. W oknie dialogowym wybierz jedną lub obie opcje. Kliknij przycisk OK. Nowy projekt "ModelBus" jest dodawany do rozwiązania DSL.

  2. Kliknij pozycję Przekształć wszystkie szablony i ponownie skompiluj rozwiązanie.

Aby wysłać obiekt ze źródłowego rozszerzenia DSL

  1. W podklasie ElementOperations zastąpij Copy() tak, aby kodował odwołanie magistrali modelu (MBR) do obiektu IDataObject. Ta metoda zostanie wywołana, gdy użytkownik zacznie przeciągać z diagramu źródłowego. Zakodowany MBR będzie następnie dostępny w obiekcie IDataObject, gdy użytkownik spadnie na diagramie docelowym.

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

Aby otrzymać odwołanie do magistrali modelu z rozszerzenia DSL w docelowym projekcie DSL lub UML

  1. W docelowym projekcie DSL dodaj odwołania do projektu:

    • Źródłowy projekt Dsl.

    • Źródłowy projekt ModelBus.

  2. W pliku kodu programu obsługi gestów dodaj następujące odwołania do przestrzeni 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. W poniższym przykładzie pokazano, jak 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ący z modelu UML

  • Poniższy przykładowy kod akceptuje obiekt porzucony 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
    }  }  }
    

Używanie akcji myszy: przeciąganie elementów przedziału

Można napisać procedurę obsługi, która przechwytuje akcje myszy w polach kształtu. Poniższy przykład pozwala użytkownikowi zmienić kolejność elementów w przedziale, przeciągając myszą.

Aby utworzyć ten przykład, utwórz rozwiązanie przy użyciu szablonu rozwiązania Diagramy klas. Dodaj plik kodu i dodaj następujący kod. Dostosuj przestrzeń nazw tak, aby był taka sama jak własna.

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

Uwaga

Składnik Przekształcanie szablonu tekstu jest automatycznie instalowany w ramach obciążenia programistycznego rozszerzenia programu Visual Studio. Można go również zainstalować na karcie Poszczególne składniki Instalator programu Visual Studio w kategorii Zestawy SDK, biblioteki i struktury. Zainstaluj składnik Zestawu SDK modelowania na karcie Poszczególne składniki.