방법: 끌어서 놓기 처리기 추가

사용자가 항목에 다이어그램 또는 다른 다이어그램의 다른 부분에서 끌 수 있도록를 DSL 드래그 앤 드롭 이벤트에 대해 처리기를 추가할 수 있습니다 Visual Studio.이벤트를 두 번 클릭에 대 한 처리기를 추가할 수도 있습니다.두 번 클릭 및 끌어서 놓기 처리기로 알려져 있습니다 제스처 처리기.

이 항목에서 발생 하는 드래그 앤 드롭 제스처 다른 다이어그램에 설명 합니다.이동 및 복사 이벤트에 대해 단일 다이어그램 내에서 서브 클래스 정의의 대 안으로 고려 ElementOperations.자세한 내용은 방법: 프로그램 복사 및 붙여넣기 동작 - 리디렉션를 참조하십시오.DSL 정의 사용자 지정할 수도 있습니다.

항목 내용

  • 처음 두 섹션이 제스처 처리기를 정의 하는 다른 방법에 설명 합니다.

    • 제스처 처리기를 재정의 하는 ShapeElement 메서드에 의해 정의.OnDragDropOnDoubleClick, OnDragOver, 및 다른 메서드를 재정의할 수 있습니다.

    • MEF를 사용 하 여 동작 처리기 정의.타사 개발자를 DSL 자체 처리기를 정의할 수 있도록이 메서드를 사용 합니다.DSL을 설치한 타사 확장 프로그램을 설치 하려면 사용자가 선택할 수 있습니다.

  • 끌어 온된 항목을 디코딩하는 방법.창 또는 바탕 화면에서 뿐 DSL에서 요소를 끌 수 있습니다.

  • 원래 하는 항목을 끌어.끌어 온된 항목 DSL 요소인 경우 원본 모델을 열고 액세스할 수 있습니다.

  • 마우스를 사용 하 여: 구획 항목 끌기.이 샘플에서는 가로채 마우스 동작에 대 한 셰이프 필드에는 하위 수준 처리기를 보여 줍니다.예제 항목에는 마우스를 드래그 하 여 순서를 변경할 수가 있습니다.

ShapeElement 메서드를 재정의 하 여 동작 처리기를 정의 합니다.

DSL 프로젝트에 새 코드 파일을 추가 합니다.제스처 처리기에서는 일반적으로 적어도 있어야 using 문의 하십시오.

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

새 파일을 끌기 작업에 응답 해야 하는 도형 또는 다이어그램 클래스의 partial 클래스를 정의 합니다.다음 메서드를 재정의 합니다.

  • OnDragOver-이 메서드는 끌기 작업 도중 마우스 포인터가 도형에 진입 하면 호출 됩니다.메서드를 사용자가 드래그 하는 항목을 검사 하 고 사용자가 항목이이 셰이프를 삭제할 수 있는지 여부를 나타내는 효과 속성을 설정 해야 합니다.이 셰이프 위에 고도 결정 하는 동안 커서 모양이 효과 속성 결정 여부 OnDragDrop() 마우스 단추를 놓을 때 호출 됩니다.

    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–이 도형 또는 다이어그램 위에 마우스 포인터가 있을 때 마우스 단추 경우 놓을 경우이 메서드를 호출 OnDragOver(DiagramDragEventArgs e) 이전에 설정 된 e.Effect 이 아닌 다른 값으로 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-이 메서드는 다이어그램을 클릭할 때 호출 됩니다.

    자세한 내용은 방법: 모양 또는 데코레이터 클릭 가로채기를 참조하십시오.

정의 IsAcceptableDropItem(e) 여부는 끌어 온된 항목을 사용할 수 ProcessDragDropItem(e) 항목을 삭제 하면 모델을 업데이트 하 고 결정 합니다.이러한 메서드를 이벤트 인수에서 항목 먼저 추출 해야 합니다.이렇게 하는 방법에 대 한 자세한 내용은 는 끌어 온된 항목에 대 한 참조를 가져올 수.

MEF를 사용 하 여 동작 처리기를 정의 합니다.

MEF (관리 되는 확장성 프레임 워크) 최소한의 구성으로 설치할 수 있는 구성 요소를 정의할 수 있습니다.자세한 내용은 MEF(Managed Extensibility Framework)를 참조하십시오.

MEF 제스처 처리기를 정의.

  1. 추가 사용자 DslDslPackage 프로젝트는 MefExtension 에서 설명 하는 파일 MEF를 사용하여 DSL 확장.

  2. 이제는 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);
       }
    
    

    여러 종류의 개체를 끌어 온된 경우와 같이 둘 이상의 제스처 처리기 구성 요소를 만들 수 있습니다.

  3. 대상 도형, 연결선 또는 다이어그램 클래스에 대 한 partial 클래스 정의 추가 하 고 메서드 정의 IsAcceptableDropItem() 및 ProcessDragDropItem().이러한 메서드의 이벤트 인수에서 끌어 온된 항목을 추출 하 여 시작 해야 합니다.자세한 내용은 는 끌어 온된 항목에 대 한 참조를 가져올 수.

끌어 온된 항목을 디코딩하는 방법

때 사용자가 해당 다이어그램으로 끌 또는 다른 다이어그램의 한 부분에서 드래그 하는 항목에 대 한 정보를 사용할 수 있습니다 [DiagramDragEventArgs].한 화면에 모든 개체 끌기 작업이 시작 수 있기 때문에 데이터 다양 한 형식 중 하나로 사용할 수 있습니다.코드를 처리할 수 있습니다 형식 인식 해야 합니다.

디버깅 모드 항목에 중단점 설정, 끌기 소스 정보는 사용 가능한 형식을 검색 하려면 코드를 실행 OnDragOver() 또는 CanDragDrop().검사 값은 DiagramDragEventArgs 매개 변수.정보는 두 가지 형태로 제공 됩니다.

  • IDataObject Data–이 속성이 serialize 된 버전의 원본 개체가 일반적으로 둘 이상의 형식으로 전달합니다.가장 유용한 기능입니다.

    • diagramEventArgs.Data.GetDataFormats() – 끌어온된 개체를 디코딩할 수 있는 형식 목록을 표시 합니다.예를 들어, 사용자가 바탕 화면에서 파일을 끌 경우 파일 이름을 사용할 수 있는 형식을 포함 ("FileNameW").

    • diagramEventArgs.Data.GetData(format)– 끌어온된 개체를 지정 된 형식으로 디코딩합니다.개체를 적절 한 형식으로 캐스팅 합니다.예를 들면 다음과 같습니다.

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

      또한 사용자 고유의 사용자 지정 형식으로 원본에서 모델 버스 참조와 같은 개체를 전송할 수 있습니다.자세한 내용은 를 보낼 모델 버스 참조에서 드래그 앤 드롭 하는 방법.

  • ElementGroupPrototypePrototype– DSL 또는 UML 모델에서 항목을 끌어 사용자가이 속성을 사용 합니다.요소 그룹 프로토타입에 하나 이상의 개체, 링크 및 해당 속성 값을 포함합니다.붙여 넣기 작업 및 도구 상자에서 요소를 추가 하는 경우에 사용 됩니다.프로토타입 객체 및 유형을 Guid로 식별 됩니다.예를 들어,이 코드 클래스 요소 UML 다이어그램 또는 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
    }
    

    UML 셰이프를 받아들이도록 실험에 의해 UML 셰이프 클래스 Guid를 확인 합니다.다이어그램에서 요소를 두 개 이상의 형식이 일반적으로 임을 기억 하십시오.또한 DSL 또는 UML 다이어그램에서 끌어 온 개체 모델 요소 셰이프를 구분 합니다.

DiagramDragEventArgs또한 현재 마우스 포인터 위치 및 사용자가 ctrl 키, alt 키 또는 SHIFT 키 눌러 됩니다 여부를 나타내는 속성이 있습니다.

원래 드래그 요소를 얻는 방법

Data 및 Prototype 속성에는 이벤트 인수 끌어 놓은 모양에 대 한 참조만 포함 되어 있습니다.프로토타입 방식으로 파생 된 DSL 대상 개체를 만들 경우 일반적으로 원본에 액세스할 수 예를 들어, 파일 내용 읽기, 도형으로 표시 하는 모델 요소를 탐색 하면.이를 위해 Visual Studio 모델 버스를 사용할 수 있습니다.

DSL 프로젝트 모델 버스를 준비 하려면

  • DSL 원본으로 액세스할 수 있도록 Visual Studio 모델 버스.

    1. 다운로드 하 고 설치 하지 않은 경우 Visual Studio 모델 버스 확장을 설치 합니다.자세한 내용은 시각화 및 모델링 SDK.

    2. DSL 정의 파일 원본의 DSL에서 DSL 디자이너를 엽니다.디자인 화면을 마우스 오른쪽 단추로 클릭 하 고 다음을 클릭 사용 Modelbus.대화 상자에 있는 옵션 중 하나 또는 모두를 선택 합니다.확인을 클릭합니다.새 프로젝트 "ModelBus" DSL 솔루션에 추가 됩니다.

    3. 클릭 모든 템플릿 변환 하 고 솔루션을 다시 빌드합니다.

원본의 DSL 개체 보내기

  • ElementOperations 하위 클래스에서 재정의 Copy() 하 여 Idataobject에 모델 버스 참조 (MBR)를 인코딩합니다.이 메서드는 사용자 소스 다이어그램에서 끌기 시작할 때 호출 됩니다.사용자는 대상 다이어그램에서 떨어지면 인코딩된 MBR에 다음 Idataobject에 사용할 수 있습니다.

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

모델 버스 참조 대상 DSL 또는 UML 프로젝트에서는 DSL에서 받을 수

  1. 대상 DSL 프로젝트에 프로젝트 참조를 추가 합니다.

    • Dsl 프로젝트입니다.

    • ModelBus 프로젝트입니다.

  2. 동작 처리기 코드 파일에는 다음과 같은 네임 스페이스 참조를 추가 합니다.

    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. 다음 샘플 소스 모델 요소에 액세스 하는 방법을 보여 줍니다.

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

UML 모델을 기반으로 요소를 적용 합니다.

  • 다음 코드 예제에서는 개체를 받아들이는 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 
    }  }  }
    

구획 항목 끌기 마우스를 사용 하 여:

셰이프 필드에서 마우스 동작을 차단 하는 처리기를 작성할 수 있습니다.다음 예제에서는 항목에는 마우스를 드래그 하 여 순서를 변경할 수가 있습니다.

사용 하 여이 예제를 빌드하려면 솔루션 만들기는 클래스 다이어그램 솔루션 템플릿.코드 파일을 추가 하 고 다음 코드를 추가 합니다.네임 스페이스는 사용자 고유의 것으로 조정 합니다.

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

참고 항목

개념

복사 동작 사용자 지정

방법: 프로그램 복사 및 붙여넣기 동작 - 리디렉션