Compartilhar via


Personalizar o comportamento de cópia

Em um idioma específico do domínio (DSL), criado com o Visual Studio visualização e modelagem SDK, você pode alterar o que acontece quando o usuário copia e cola elementos.

Cópia padrão e o comportamento de colagem

Para ativar a cópia, defina a Permitem copiar colar propriedade da Editor nó no Explorer DSL.

Por padrão, quando o usuário copiar elementos para a área de transferência, os elementos a seguir também são copiados:

  • Incorporado descendentes dos elementos selecionados.(Ou seja, elementos que são os alvos de incorporar os relacionamentos que são originados em copiado elementos).

  • Links de relacionamento entre os elementos copiados.

Essa regra se aplica recursivamente para os elementos copiados e os links.

Elementos copiados e colados

Os elementos copiados e os links são serializados e armazenados em um ElementGroupPrototype (EGP), que é colocado na área de transferência.

Uma imagem dos elementos copiados também é colocada na área de transferência.Isso permite ao usuário colar em outros aplicativos, como o Word.

O usuário pode colar elementos copiados para um destino que pode aceitar os elementos de acordo com a definição de DSL.Por exemplo, em uma DSL gerada a partir do modelo de solução de componentes, o usuário pode colar as portas em componentes, mas não para o diagrama; e pode colar componentes para o diagrama, mas não em outros componentes.

Personalizando a cópia e comportamento de colagem

Para obter mais informações sobre como personalizar o modelo usando o código de programa, consulte Navegando e atualizando um modelo de código de programa.

  • Habilitar ou desabilitar a copiar, recortar e colar.
    No Explorer DSL, defina a Permitem copiar colar propriedade da Editor nó.

  • Copie os links para o mesmo destino. Por exemplo, para ter uma caixa de comentário copiado vinculados ao mesmo elemento de assunto.
    Definir o Cópia propaga a propriedade da função de cópia propagar para vincular apenas.Para obter mais informações, consulte Personalizar o comportamento do Link Copy.

  • Copie elementos vinculados. Por exemplo, quando você copia um novo elemento, cópias de todas as caixas de comentário vinculadas são feitas também.
    Definir o Propaga Copy a propriedade da função de cópia propagar para o link e oposto.Para obter mais informações, consulte Personalizar o comportamento do Link Copy.

  • Duplica rapidamente os elementos copiando e colando. Normalmente, o item que você acabou de copiar ainda está selecionado e você não pode colar o mesmo tipo de elemento para ele.
    Adicionar uma diretiva de mesclagem de elemento para a classe de domínio e defini-la como mesclagens direta para a classe pai.Isso terá o mesmo efeito sobre as operações de arrastar.Para obter mais informações, consulte Personalizando a movimentação e criação de elemento.

    - ou -

    Selecione o diagrama antes de colar os elementos, substituindo ClipboardCommandSet.ProcessOnPasteCommand().Adicione esse código em um arquivo personalizado no projeto DslPackage:

    namespace Company.MyDsl {
    using System.Linq;
    using Microsoft.VisualStudio.Modeling.Diagrams; 
    using Microsoft.VisualStudio.Modeling.Shell;
    partial class MyDslClipboardCommandSet
    {
      protected override void ProcessOnMenuPasteCommand()
      {
     // Deselect the current selection after copying:
     Diagram diagram = (this.CurrentModelingDocView as SingleDiagramDocView).Diagram;
        this.CurrentModelingDocView
         .SelectObjects(1, new object[] { diagram }, 0);
      }
    } }
    
  • Crie links adicionais quando o usuário cola até um destino selecionado. Por exemplo, quando uma caixa de comentário é colada em um elemento, um link é feito entre eles.
    Adicione uma diretiva de mesclagem do elemento para a classe de domínio de destino e defini-la para processar a mesclagem com a adição de links.Isso terá o mesmo efeito sobre as operações de arrastar.Para obter mais informações, consulte Personalizando a movimentação e criação de elemento.

    - ou -

    Substituir ClipboardCommandSet.ProcessOnPasteCommand() para criar os links adicionais depois de chamar o método base.

  • Personalizar os formatos nos quais elementos podem ser copiados para aplicativos externos – por exemplo, para adicionar uma borda para o formato de bitmap.
    Substituir MyDslClipboardCommandSet.ProcessOnMenuCopyCommand() no projeto DslPackage.

  • Personalize como os elementos são copiados para a área de transferência pelo comando copy, mas não em uma operação de arrastar.
    Substituir MyDslClipboardCommandSet.CopyModelElementsIntoElementGroupPrototype() no projeto DslPackage.

  • Preservar o layout de forma por meio de copiar e colar.
    Quando o usuário copia várias formas, você pode preservar suas posições relativas quando forem colados.Essa técnica é demonstrada pelo exemplo em VMSDK: exemplo de diagramas de circuito.

    Para obter esse efeito, adicione as formas e conectores para o ElementGroupPrototype copiado.O método mais conveniente para substituir é ElementOperations.CreateElementGroupPrototype().Para fazer isso, adicione o seguinte código ao projeto Dsl:

    public class MyElementOperations : DesignSurfaceElementOperations
    {
      // Create an EGP to add to the clipboard.
      // Called when the elements to be copied have been
      // collected into an ElementGroup.
     protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType)
      {
     // Add the shapes and connectors:
     // Get the elements already in the group:
        ModelElement[] mels = elementGroup.ModelElements
            .Concat(elementGroup.ElementLinks) // Omit if the paste target is not the diagram.
            .ToArray();
     // Get their shapes:
        IEnumerable<PresentationElement> shapes = 
           mels.SelectMany(mel => 
                PresentationViewsSubject.GetPresentation(mel));
        elementGroup.AddRange(shapes);
    
     return base.CreateElementGroupPrototype
               (elementGroup, elements, closureType);
      }
    
     public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram)
          : base(serviceProvider, diagram)
      { }
    }
    
    // Replace the standard ElementOperations
    // singleton with your own:
    partial class MyDslDiagram // EDIT NAME
    {
     /// <summary>
     /// Singleton ElementOperations attached to this diagram.
     /// </summary>
     public override DesignSurfaceElementOperations ElementOperations
      {
     get
        {
     if (singleton == null)
          {
            singleton = new MyElementOperations(this.Store as IServiceProvider, this);
          }
     return singleton;
        }
      }
     private MyElementOperations singleton = null;
    }
    
  • Colar formas em um local escolhido, como, por exemplo, a posição atual do cursor.
    Quando o usuário copia várias formas, você pode preservar suas posições relativas quando forem colados.Essa técnica é demonstrada pelo exemplo em VMSDK: exemplo de diagramas de circuito.

    Para obter esse efeito, substituir ClipboardCommandSet.ProcessOnMenuPasteCommand() para usar a versão específica do local do ElementOperations.Merge().Para fazer isso, adicione o seguinte código no projeto DslPackage:

    
    partial class MyDslClipboardCommandSet // EDIT NAME
    {
       /// <summary>
        /// This method assumes we only want to paste things onto the diagram
        /// - not onto anything contained in the diagram.
        /// The base method pastes in a free space on the diagram.
        /// But if the menu was used to invoke paste, we want to paste in the cursor position.
        /// </summary>
        protected override void ProcessOnMenuPasteCommand()
        {
    
      NestedShapesSampleDocView docView = this.CurrentModelingDocView as NestedShapesSampleDocView;
    
          // Retrieve data from clipboard:
          System.Windows.Forms.IDataObject data = System.Windows.Forms.Clipboard.GetDataObject();
    
          Diagram diagram = docView.CurrentDiagram;
          if (diagram == null) return;
    
          if (!docView.IsContextMenuShowing)
          {
            // User hit CTRL+V - just use base method.
    
            // Deselect anything that's selected, otherwise
            // pasted item will be incompatible:
            if (!this.IsDiagramSelected())
            {
              docView.SelectObjects(1, new object[] { diagram }, 0);
            }
    
            // Paste into a convenient spare space on diagram:
        base.ProcessOnMenuPasteCommand();
          }
          else
          {
            // User right-clicked - paste at mouse position.
    
            // Utility class:
            DesignSurfaceElementOperations op = diagram.ElementOperations;
    
            ShapeElement pasteTarget = diagram;
    
            // Check whether what's in the paste buffer is acceptable on the target.
            if (pasteTarget != null && op.CanMerge(pasteTarget, data))
            {
    
            // Although op.Merge would be a no-op if CanMerge failed, we check CanMerge first
              // so that we don't create an empty transaction (after which Undo would be no-op).
              using (Transaction t = diagram.Store.TransactionManager.BeginTransaction("paste"))
              {
                PointD place = docView.ContextMenuMousePosition;
                op.Merge(pasteTarget, data, PointD.ToPointF(place));
                t.Commit();
              }
            }
          }
        }
      }
    
  • Permitir que o usuário arraste e solte os elementos.
    Consulte Como: adicionar um manipulador de arrastar-e-soltar.

Quando o usuário copia um elemento, o comportamento padrão é que todos os elementos incorporados também são copiados.Você pode modificar o padrão de comportamento de cópia.Na definição de DSL, selecione uma função em um lado de um relacionamento e no conjunto de janela de propriedades do Propaga Copy valor.

Propaga-se a propriedade Copy da função de domínio

Existem três valores:

  • Não propagar a cópia

  • Propagar a cópia para vincular apenas - quando o grupo é colado, a nova cópia desse link fará referência ao elemento existente na outra extremidade do link.

  • Propagar a cópia para vincular e oposto - o grupo de copiado inclui uma cópia do elemento na outra extremidade do link.

Efeito de cópia com PropagateCopyToLinkOnly

As alterações que você fizer afetará os elementos e a imagem que será copiada.

Cópia de programação e o comportamento de colagem

Muitos aspectos do comportamento de uma DSL com relação ao copiar, colar, criação e exclusão de objetos são regidos por uma instância de ElementOperations que está acoplada ao diagrama.Você pode modificar o comportamento do seu DSL derivando sua própria classe de ElementOperations e substituindo o ElementOperations a propriedade da sua classe de diagrama.

DicaDica

Para obter mais informações sobre como personalizar o modelo usando o código de programa, consulte Navegando e atualizando um modelo de código de programa.

Diagrama de seqüência para a operação de cópiaDiagrama de seqüência de operação de colagem

Para definir seu próprio ElementOperations

  1. Em um novo arquivo em seu projeto DSL, crie uma classe que é derivada de DesignSurfaceElementOperations.

  2. Adicione uma definição de classe parcial para sua classe de diagrama.O nome dessa classe pode ser encontrado em Dsl\GeneratedCode\Diagrams.cs.

    Na classe diagrama, substituir ElementOperations para retornar uma instância da sua subclasse de ElementOperations.Você deve retornar a mesma instância de cada chamada.

Adicione esse código em um arquivo de código personalizado no projeto DslPackage:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;

  public partial class MyDslDiagram
  {
    public override DesignSurfaceElementOperations ElementOperations
    {
      get
      {
        if (this.elementOperations == null)
        {
          this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
        }
        return this.elementOperations;
      }
    }
    private MyElementOperations elementOperations = null;
  }

  public class MyElementOperations : DesignSurfaceElementOperations
  {
    public MyElementOperations(IServiceProvider serviceProvider, MyDslDiagram diagram)
      : base(serviceProvider, diagram)
    { }
    // Overridden methods follow
  }

Recebimento de itens arrastado de outros modelos

ElementOperations também pode ser usado para definir o comportamento de copiar, mover, exclusão e arrastar-e-soltar.Como uma demonstração do uso de ElementOperations, o exemplo fornecido aqui define o comportamento personalizado de arrastar-e-soltar.No entanto, para esse fim você pode considerar a abordagem alternativa descrita em Como: adicionar um manipulador de arrastar-e-soltar, que é mais extensível.

Defina os dois métodos na classe ElementOperations:

  • CanMerge(ModelElement targetElement, System.Windows.Forms.IDataObject data)que determina se o elemento de origem pode ser arrastado para a forma de destino, o conector ou o diagrama.

  • MergeElementGroupPrototype(ModelElement targetElement, ElementGroupPrototype sourcePrototype)que combina o elemento de origem no destino.

Ff521398.collapse_all(pt-br,VS.110).gifCanMerge()

[CanMerge()]é chamado para determinar o feedback que deve ser dada ao usuário conforme o mouse se move no diagrama.Os parâmetros do método são o elemento através do qual o mouse está passando e dados sobre a origem da qual a operação de arrastar foi realizada.O usuário pode arrastar em qualquer lugar na tela.Portanto, o objeto de origem pode ser de vários tipos diferentes e pode ser serializado em formatos diferentes.Se a fonte for um modelo UML ou DSL, o parâmetro de dados é a serialização de um ElementGroupPrototype.Operações de arrastar, a cópia e a caixa de ferramentas usam ElementGroupPrototypes para representar os fragmentos dos modelos.

Um protótipo de grupo de elemento pode conter qualquer número de elementos e links.Tipos de elementos podem ser identificados por seus GUIDs.O GUID é da forma que foi arrastado, não o elemento de modelo subjacente.No exemplo a seguir, CanMerge() retorna true se uma forma de classe de um diagrama UML é arrastada sobre este diagrama.

public override bool CanMerge(ModelElement targetShape, System.Windows.Forms.IDataObject data)
 {
  // Extract the element prototype from the data.
  ElementGroupPrototype prototype = ElementOperations.GetElementGroupPrototype(this.ServiceProvider, data);
  if (targetShape is MyTargetShape && prototype != null &&
        prototype.RootProtoElements.Any(rootElement => 
          rootElement.DomainClassId.ToString() 
          ==  "3866d10c-cc4e-438b-b46f-bb24380e1678")) // Guid of UML Class shapes
          // or SourceClass.DomainClassId
        return true;
   return base.CanMerge(targetShape, data);
 }

MergeElementGroupPrototype()

Esse método é chamado quando o usuário solta um elemento em um diagrama, uma forma ou um conector.Ele deve mesclar o conteúdo arrastado o elemento de destino.Neste exemplo, o código determina se ele reconhece a combinação de tipos de protótipo e de destino; Nesse caso, o método converte os elementos arrastados um protótipo dos elementos que devem ser adicionados ao modelo.O método base é chamado para realizar a mesclagem, qualquer um dos elementos não convertidos ou convertidos.

    public override void MergeElementGroupPrototype(ModelElement targetShape, ElementGroupPrototype sourcePrototype)
    {
      ElementGroupPrototype prototypeToMerge = sourcePrototype;
      MyTargetShape pel = targetShape as MyTargetShape;
      if (pel != null)
      {
        prototypeToMerge = ConvertDraggedTypeToLocal(pel, sourcePrototype);
      }
      if (prototypeToMerge != null)
        base.MergeElementGroupPrototype(targetShape, prototypeToMerge);
    }

Este exemplo lida com elementos de classe UML arrastados de um diagrama de classe UML.O DSL não foi projetado para armazenar classes UML diretamente, mas em vez disso, podemos criar um elemento DSL para cada classe UML arrastado.Isso seria útil, por exemplo, se o DSL é um diagrama de instância.O usuário pode arrastar as classes para o diagrama para criar instâncias dessas classes.

    private ElementGroupPrototype ConvertDraggedTypeToLocal (MyTargetShape snapshot, ElementGroupPrototype prototype)
    {
      // Find the UML project:
      EnvDTE.DTE dte = snapshot.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
      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) continue;
        // Look for the shape that was dragged:
        foreach (IDiagram umlDiagram in store.Diagrams())
        {
          // Get modeling diagram that implements UML diagram:
          Diagram diagram = umlDiagram.GetObject<Diagram>();
          Guid elementId = prototype.SourceRootElementIds.FirstOrDefault();
          ShapeElement shape = diagram.Partition.ElementDirectory.FindElement(elementId) as ShapeElement;
          if (shape == null) continue;
          IClass classElement = shape.ModelElement as IClass;
          if (classElement == null) continue;
          
          // Create a prototype of elements in my DSL, based on the UML element:
          Instance instance = new Instance(snapshot.Store);
          instance.Type = classElement.Name;
          // Pack them into a prototype:
          ElementGroup group = new ElementGroup(instance);
          return group.CreatePrototype();
        }
      }
      return null;
    }

Comportamento padrão de cópia

O código nesta seção mostra os métodos que você podem substituir para alterar o comportamento de cópia.Para ajudá-lo a aprender a alcançar suas personalizações, esta seção mostra o código que substitui os métodos envolvidos na cópia, mas não altera o comportamento padrão.

Quando o usuário pressiona CTRL + C ou usa o comando Copy, o método ProcessOnMenuCopyCommand é chamado.Você pode ver como isso é configurado DslPackage\Generated Code\CommandSet.cs.Para obter mais informações sobre como os comandos são configurados, consulte Como: adicionar um comando ao Menu de atalho.

Você pode substituir o ProcessOnMenuCopyCommand adicionando uma definição de classe parcial do MyDslClipboardCommandSet no projeto DslPackage.

using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

partial class MyDslClipboardCommandSet
{
  /// <summary>
  /// Override ProcessOnMenuCopyCommand() to copy elements to the
  /// clipboard in different formats, or to perform additional tasks
  /// before or after copying – for example deselect the copied elements.
  /// </summary>
  protected override void ProcessOnMenuCopyCommand()
  {
    IList<ModelElement> selectedModelElements = this.SelectedElements;
    if (selectedModelElements.Count == 0) return;

    // System container for clipboard data.
    // The IDataObject can contain data in several formats.
    IDataObject dataObject = new DataObject();
      
    Bitmap bitmap = null; // For export to other programs.
    try
    {
      #region Create EGP for copying to a DSL.
      this.CopyModelElementsIntoElementGroupPrototype
                     (dataObject, selectedModelElements);
      #endregion
      
      #region Create bitmap for copying to another application. 
      // Find all the shapes associated with this selection:
      List<ShapeElement> shapes = new List<ShapeElement>(
        this.ResolveExportedShapesForClipboardImages
              (dataObject, selectedModelElements));

      bitmap = this.CreateBitmapForClipboard(shapes);
      if (bitmap != null)
      {
        dataObject.SetData(DataFormats.Bitmap, bitmap);
      }
      #endregion 
     
      // Add the data to the clipboard:
      Clipboard.SetDataObject(dataObject, true, 5, 100);
    }
    finally
    {
      // Dispose bitmap after SetDataObject:
      if (bitmap != null) bitmap.Dispose();
    }
  }
/// <summary>
/// Override this to customize the element group that is copied to the clipboard.
/// </summary>
protected override void CopyModelElementsIntoElementGroupPrototype(IDataObject dataObject, IList<ModelElement> selectedModelElements)
{
  return this.ElementOperations.Copy(dataObject, selectedModelElements);
}
}

Cada diagrama possui uma instância singleton de ElementOperations.Você pode fornecer seu próprio derivativo.Esse arquivo, que pode ser colocado no projeto DSL, o mesmo que o código que ele substitui comportariam:

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

namespace Company.MyDsl
{
  partial class MyDslDiagram
  {
    /// <summary>
    /// Singleton ElementOperations attached to this diagram.
    /// </summary>
    public override DesignSurfaceElementOperations ElementOperations
    {
      get
      {
        if (this.elementOperations == null)
        {
          this.elementOperations = new MyElementOperations(this.Store as IServiceProvider, this);
        }
        return this.elementOperations;
      }
    }
    private MyElementOperations elementOperations = null;
  }

  // Our own version of ElementOperations so that we can override:
  public class MyElementOperations : DesignSurfaceElementOperations
  {
    public MyElementOperations(IServiceProvider serviceProvider, ElementOps1Diagram diagram)
      : base(serviceProvider, diagram)
    { }


     
    /// <summary>
    /// Copy elements to the clipboard data.
    /// Provides a hook for adding custom data.
    /// </summary>
    public override void Copy(System.Windows.Forms.IDataObject data, 
      ICollection<ModelElement> elements, 
      ClosureType closureType, 
      System.Drawing.PointF sourcePosition)
    {
      if (CanAddElementGroupFormat(elements, closureType))
      {
        AddElementGroupFormat(data, elements, closureType); 
      }

      // Override these to store additional data:
      if (CanAddCustomFormat(elements, closureType))
      {
        AddCustomFormat(data, elements, closureType, sourcePosition);
      }
    }
     
    
    protected override void AddElementGroupFormat(System.Windows.Forms.IDataObject data, ICollection<ModelElement> elements, ClosureType closureType)
    {
      // Add the selected elements and those implied by the propagate copy rules:
      ElementGroup elementGroup = this.CreateElementGroup(elements, closureType);

      // Mark all the elements that are not embedded under other elements:
      this.MarkRootElements(elementGroup, elements, closureType);

      // Store in the clipboard data:
      ElementGroupPrototype elementGroupPrototype = this.CreateElementGroupPrototype(elementGroup, elements, closureType);
      data.SetData(ElementGroupPrototype.DefaultDataFormatName, elementGroupPrototype);
    }

    /// <summary>
    /// Override this to store additional elements in the element group:
    /// </summary>
    protected override ElementGroupPrototype CreateElementGroupPrototype(ElementGroup elementGroup, ICollection<ModelElement> elements, ClosureType closureType)
    {
      ElementGroupPrototype prototype = new ElementGroupPrototype(this.Partition, elementGroup.RootElements, elementGroup);
      return prototype;
    }

    /// <summary>
    /// Create an element group from the given starting elements, using the 
    /// copy propagation rules specified in the DSL Definition.
    /// By default, this includes all the embedded descendants of the starting elements,
    /// and also includes reference links where both ends are already included.
    /// </summary>
    /// <param name="startElements">model elements to copy</param>
    /// <param name="closureType"></param>
    /// <returns></returns>
    protected override ElementGroup CreateElementGroup(ICollection<ModelElement> startElements, ClosureType closureType)
    {
      // ElementClosureWalker finds all the connected elements, 
      // according to the propagate copy rules specified in the DSL Definition:
      ElementClosureWalker walker = new ElementClosureWalker(this.Partition, 
        closureType, // Normally ClosureType.CopyClosure
        startElements, 
        true, // Do not load other models.
        null, // Optional list of domain roles not to traverse.
        true); // Include relationship links where both ends are already included.
      
      walker.Traverse(startElements);
      IList<ModelElement> closureList = walker.ClosureList;
      Dictionary<object, object> closureContext = walker.Context;

      // create a group for this closure
      ElementGroup group = new ElementGroup(this.Partition);
      group.AddRange(closureList, false);

      // create the element group prototype for the group
      foreach (object key in closureContext.Keys)
      {
        group.SourceContext.ContextInfo[key] = closureContext[key];
      }

      return group;
    }
  }
}

Consulte também

Conceitos

Personalizando a movimentação e criação de elemento

Como: adicionar um manipulador de arrastar-e-soltar

Personalizar o comportamento de exclusão

Outros recursos

Exemplo: Exemplo de diagramas de circuito VMSDK