Como adicionar um manipulador de evento de arrastar e soltarHow to: Add a Drag-and-Drop Handler

Você pode adicionar manipuladores para eventos de arrastar e soltar à sua DSL, para que os usuários possam arrastar itens para o diagrama de outros diagramas ou de outras partes do Visual Studio.You can add handlers for drag-and-drop events to your DSL, so that users can drag items onto your diagram from other diagrams or from other parts of Visual Studio. Também é possível adicionar manipuladores de eventos como cliques duplos.You can also add handlers for events such as double-clicks. Juntos, os manipuladores do tipo "arrastar e soltar" e "clicar duas vezes" são conhecidos como manipuladores de gestos.Together, drag-and-drop and double-click handlers are known as gesture handlers.

Este tópico discute gestos de arrastar e soltar originados em outros diagramas.This topic discusses drag-and-drop gestures that originate on other diagrams. Para mover e copiar eventos dentro de um único diagrama, considere a alternativa de definir uma subclasse de ElementOperations.For move and copy events within a single diagram, consider the alternative of defining a subclass of ElementOperations. Para obter mais informações, consulte Personalizando o comportamento de cópia.For more information, see Customizing Copy Behavior. Também poderá ser possível personalizar a definição da DSL.You might also be able to customize the DSL definition.

Definindo manipuladores de gestos substituindo métodos ShapeElementDefining Gesture Handlers by Overriding ShapeElement Methods

OnDragDrop, OnDoubleClick , OnDragOver e outros métodos podem ser substituídos.OnDragDrop, OnDoubleClick, OnDragOver, and other methods can be overridden.

Adicione um novo arquivo de código ao projeto DSL.Add a new code file to your DSL project. Para um manipulador de gestos, geralmente você deve ter pelo menos as seguintes using diretivas:For a gesture handler, you usually must have at least the following using directives:

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

No novo arquivo, defina uma classe parcial da classe da forma ou do diagrama que deve responder à operação de arrastar.In the new file, define a partial class for the shape or diagram class that should respond to the drag operation. Substitua os seguintes métodos:Override the following methods:

  • OnDragOver-Esse método é chamado quando o ponteiro do mouse entra na forma durante uma operação de arrastar.OnDragOver- This method is called when the mouse pointer enters the shape during a drag operation. O método deve inspecionar o item que o usuário está arrastando e definir a propriedade Efeito para indicar se o usuário pode soltar o item nessa forma.Your method should inspect the item that the user is dragging, and set the Effect property to indicate whether the user can drop the item on this shape. A propriedade Efeito determina a aparência do cursor enquanto estiver sobre a forma e também determina se OnDragDrop() será chamado quando o usuário soltar o botão do mouse.The Effect property determines the appearance of the cursor while it is over this shape, and also determines whether OnDragDrop() will be called when the user releases the mouse button.

    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 -Esse método será chamado se o usuário liberar o botão do mouse enquanto o ponteiro do mouse estiver sobre esta forma ou diagrama, se OnDragOver(DiagramDragEventArgs e) definido anteriormente e.Effect como um valor diferente de None .OnDragDrop - This method is called if the user releases the mouse button while the mouse pointer rests over this shape or diagram, if OnDragOver(DiagramDragEventArgs e) previously set e.Effect to a value other than 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 -Esse método é chamado quando o usuário clica duas vezes na forma ou no diagrama.OnDoubleClick - This method is called when the user double-clicks the shape or diagram.

    Para obter mais informações, consulte como interceptar um clique em uma forma ou decorador.For more information, see How to: Intercept a Click on a Shape or Decorator.

Defina IsAcceptableDropItem(e) para determinar se o item arrastado é aceitável e ProcessDragDropItem(e) para atualizar o modelo quando o item for solto.Define IsAcceptableDropItem(e) to determine whether the dragged item is acceptable, and ProcessDragDropItem(e) to update your model when the item is dropped. Esses métodos devem primeiro extrair o item dos argumentos do evento.These methods must first extract the item from the event arguments. Para obter informações sobre como fazer isso, consulte como obter uma referência para o item arrastado.For information about how to do that, see How to get a reference to the dragged item.

Definir manipuladores de gestos usando o MEFDefine Gesture Handlers by using MEF

Use esse método se desejar permitir a desenvolvedores terceiros definir seus próprios manipuladores à DSL.Use this method if you want third-party developers to be able to define their own handlers to your DSL. Usuários podem escolher instalar as extensões de terceiros após instalar a DSL.Users can choose to install the third-party extensions after they have installed your DSL.

MEF (Managed Extensibility Framework) permite definir componentes que podem ser instalados com configuração mínima.MEF (Managed Extensibility Framework) lets you define components that can be installed with minimal configuration. Para saber mais, confira Managed Extensibility Framework (MEF).For more information, see Managed Extensibility Framework (MEF).

Para definir um manipulador de gestos de MEFTo define a MEF gesture handler

  1. Adicione aos projetos DSL e DslPackage os arquivos MEFEXTENSION descritos em estender sua DSL usando o MEF.Add to your Dsl and DslPackage projects the MefExtension files that are described in Extend your DSL by using MEF.

  2. Agora é possível definir um manipulador de gestos como um componente MEF:You can now define a gesture handler as a MEF component:

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

    É possível criar mais de um componente de manipulador de gestos, como quando existem diversos tipos de objetos arrastados.You can create more than one gesture handler component, such as when you have different types of dragged objects.

  3. Adicione definições de classe parcial para as classes de forma, conector ou diagrama de destino e defina os métodos IsAcceptableDropItem() e ProcessDragDropItem().Add partial class definitions for the target shape, connector or diagram classes, and define the methods IsAcceptableDropItem() and ProcessDragDropItem(). Esses métodos devem começar extraindo o item arrastado dos argumentos do evento.These methods must begin by extracting the dragged item from the event arguments. Para obter mais informações, consulte como obter uma referência para o item arrastado.For more information, see How to get a reference to the dragged item.

Como decodificar o item arrastadoHow to decode the dragged item

Elementos podem ser arrastados de qualquer janela ou da área de trabalho, bem como de uma DSL.Elements can be dragged from any window or from the desktop, as well as from a DSL.

Quando o usuário arrasta um item para o diagrama ou de uma parte do diagrama para outra, as informações sobre o item que está sendo arrastado estão disponíveis em DiagramDragEventArgs.When the user drags an item onto your diagram, or from one part of your diagram to another, information about the item that is being dragged is available in DiagramDragEventArgs. Como a operação de arrastar pode ter começado em qualquer objeto na tela, os dados podem estar disponíveis em qualquer um entre uma variedade de formatos.Because the drag operation could have started at any object on the screen, the data can be available in any one of a variety of formats. O código deve reconhecer os formatos com os quais é capaz de lidar.Your code must recognize the formats with which it is capable of dealing.

Para saber os formatos nos quais as informações de origem do arrasto estão disponíveis, execute o código em modo de depuração, definindo um ponto de interrupção na entrada para OnDragOver() ou CanDragDrop().To discover the formats in which your drag source information is available, run your code in debugging mode, setting a breakpoint at the entry to OnDragOver() or CanDragDrop(). Inspecione os valores do parâmetro DiagramDragEventArgs.Inspect the values of the DiagramDragEventArgs parameter. As informações são fornecidas em dois formulários:The information is provided in two forms:

  • IDataObject Data -Essa propriedade transporta versões serializadas dos objetos de origem, geralmente em mais de um formato.IDataObject Data - This property carries serialized versions of the source objects, usually in more than one format. Suas funções mais úteis são:Its most useful functions are:

    • diagrameventargs. Data. GetDataFormats () – lista os formatos nos quais você pode decodificar o objeto arrastado.diagramEventArgs.Data.GetDataFormats() - Lists the formats in which you can decode the dragged object. Por exemplo, se o usuário arrastar um arquivo da área de trabalho, os formatos disponíveis incluem o nome de arquivo ("FileNameW").For example, if the user drags a file from the desktop, the available formats include the file name ("FileNameW").

    • diagramEventArgs.Data.GetData(format) -Decodifica o objeto arrastado no formato especificado.diagramEventArgs.Data.GetData(format) - Decodes the dragged object in the specified format. Converte o objeto para o tipo adequado.Cast the object to the appropriate type. Por exemplo:For example:

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

      Também é possível transmitir objetos como referências do Model Bus da origem em seu próprio formato personalizado.You can also transmit objects such as model bus references from the source in your own custom format. Para obter mais informações, consulte como enviar referências de barramento de modelo em um arrastar e soltar.For more information, see How to Send Model Bus References in a Drag and Drop.

  • ElementGroupPrototypePrototype-Use essa propriedade se desejar que os usuários arrastem itens de um modelo de DSL ou UML.ElementGroupPrototype Prototype - Use this property if you want users to drag items from a DSL or a UML model. Um protótipo de grupo de elementos contém um ou mais objetos, links e os valores de suas propriedades.An element group prototype contains one or more objects, links, and their property values. Também é usado em operações colar e ao adicionar um elemento da caixa de ferramentas.It is also used in paste operations and when you are adding an element from the toolbox. Em um protótipo, objetos e seus tipos são identificados por Guid.In a prototype, objects and their types are identified by Guid. Por exemplo, esse código permite ao usuário arrastar elementos de classe de um diagrama UML ou do Gerenciador de Modelos UML:For example, this code allows the user to drag class elements from a UML diagram or UML Model 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
    }
    

    Para aceitar formas UML, determine os GUIDs das classes Shape UML por experimento.To accept UML shapes, determine the GUIDs of the UML shape classes by experiment. Lembre-se de que geralmente há mais de um tipo de elemento em qualquer diagrama.Remember that there is usually more than one type of element on any diagram. Lembre-se também de que um objeto arrastado de uma DSL ou diagrama UML é a forma, não o elemento do modelo.Remember also that an object dragged from a DSL or UML diagram is the shape, not the model element.

DiagramDragEventArgs também tem propriedades que indicam a posição atual do ponteiro do mouse e se o usuário está pressionando as teclas CTRL, ALT ou SHIFT.DiagramDragEventArgs also has properties that indicate the current mouse pointer position and whether the user is pressing the CTRL, ALT, or SHIFT keys.

Como obter o original de um elemento arrastadoHow to get the original of a dragged element

Se o item arrastado for um elemento DSL, é possível abrir o modelo de origem e acessar o elemento.If the dragged item is a DSL element, you can open the source model and access the element.

As propriedades Data e Prototype dos argumentos do evento contêm apenas uma referência à forma arrastada.The Data and Prototype properties of the event arguments contain only a reference to the dragged shape. Geralmente, se desejar criar um objeto na DSL de destino que é derivada do protótipo de alguma maneira, será necessário obter acesso ao original, por exemplo, lendo o conteúdo do arquivo ou navegando até o elemento do modelo representado por uma forma.Usually, if you want to create an object in the target DSL that is derived from the prototype in some way, you need to obtain access to the original, for example, reading the file contents, or navigating to the model element represented by a shape. É possível usar o Visual Studio Model Bus para ajudar com isso.You can use Visual Studio Model Bus to help with this.

Preparar um projeto DSL para Model BusTo prepare a DSL project for Model Bus

Torne a DSL de origem acessível pelo barramento de modelo do Visual Studio:Make the source DSL accessible by Visual Studio Model Bus:

  1. Abra o arquivo de definição da DSL da DSL de origem no Designer de DSL.Open the DSL definition file of the source DSL in DSL Designer. Clique com o botão direito do mouse na superfície de design e clique em habilitar ModelBus.Right-click the design surface and then click Enable Modelbus. Na caixa de diálogo, escolha uma ou as duas opções.In the dialog box, choose one or both of the options. Clique em OK.Click OK. Um novo projeto "ModelBus" é adicionado à solução de DSL.A new project "ModelBus" is added to the DSL solution.

  2. Clique em transformar todos os modelos e recompilar a solução.Click Transform All Templates and rebuild the solution.

Enviar um objeto de uma DSL de origemTo send an object from a source DSL

  1. Na subclasse ElementOperations, substitua Copy() para codificar uma Referência do Model Bus (MBR) no IDataObject.In your ElementOperations subclass, override Copy() so that it encodes a Model Bus Reference (MBR) into the IDataObject. Esse método será chamado quando o usuário começar a arrastar do diagrama de origem.This method will be called when the user starts to drag from the source diagram. A MBR codificada estará disponível no IDataObject quando o usuário soltar no diagrama de destino.The encoded MBR will then be available in the IDataObject when the user drops in the target diagram.

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

Para receber uma Referência do Model Bus de uma DSL na DSL de destino ou no projeto UMLTo receive a Model Bus Reference from a DSL in a target DSL or UML project

  1. No projeto DSL de destino, adicione referências do projeto a:In the target DSL project, add project references to:

    • O projeto Dsl de origem.The source Dsl project.

    • O projeto ModelBus de origem.The source ModelBus project.

  2. No arquivo de código do manipulador de gestos, adicione as seguintes referências de namespace:In the gesture handler code file, add the following namespace references:

    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. O exemplo a seguir ilustra como obter acesso ao elemento do modelo de origem:The following sample illustrates how to get access to the source model element:

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

Aceitar um elemento originado em um modelo UMLTo accept an element sourced from a UML model

  • O código a seguir aceita um objeto arrastado de um diagrama UML.The following code sample accepts an object dropped from a UML diagram.

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

Usando ações do mouse: Arrastando itens de compartimentoUsing Mouse Actions: Dragging Compartment Items

Você pode escrever um manipulador que intercepta ações do mouse nos campos de uma forma.You can write a handler that intercepts mouse actions on a shape's fields. O exemplo a seguir permite que o usuário reordene os itens em um compartimento arrastando com o mouse.The following example lets the user reorder the items in a compartment by dragging with the mouse.

Para criar este exemplo, crie uma solução usando o modelo de solução diagramas de classe .To build this example, create a solution by using the Class Diagrams solution template. Adicione um arquivo de código e adicione o código a seguir.Add a code file and add the following code. Ajuste o namespace para o mesmo que o seu próprio.Adjust the namespace to be the same as your own.

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

Confira tambémSee also

Observação

O componente de transformação de modelo de texto é instalado automaticamente como parte da carga de trabalho de desenvolvimento de extensão do Visual Studio .The Text Template Transformation component is automatically installed as part of the Visual Studio extension development workload. Você também pode instalá-lo na guia componentes individuais do instalador do Visual Studio, na categoria SDKs, bibliotecas e estruturas .You can also install it from the Individual components tab of Visual Studio Installer, under the SDKs, libraries, and frameworks category. Instale o componente SDK de modelagem da guia componentes individuais .Install the Modeling SDK component from the Individual components tab.