Partilhar via


Como definir um manipulador de gesto em um diagrama de modelagem

No Visual Studio Ultimate, você pode definir os comandos que são executados quando o usuário clica duas vezes ou arrasta itens em um diagrama de UML. Você pode empacotar essas extensões em uma Extensão de Integração do Visual Studio (VSIX) e distribuí-la a outros usuários do Visual Studio Ultimate.

Se já houver um comportamento interno para o tipo de diagrama e o tipo de elemento que você deseja arrastar, você não poderá adicionar ou substituir esse comportamento.

Requisitos

Criando um manipulador de gesto

Para definir um manipulador de gesto para um designer UML, você deve criar uma classe que define o comportamento do manipulador de gesto e inserir essa classe em um VSIX (Extensão de Integração do Visual Studio). O VSIX atua como um contêiner que pode instalar o manipulador. Há dois métodos alternativos de definição de um manipulador de gesto:

  • Crie um manipulador do gesto em seu próprio VSIX usando um modelo de projeto. Esse é o método mais rápido. Use-o se você não deseja combinar seu manipulador com outros tipos de extensão, como extensões de validação, itens da caixa de ferramentas personalizada ou comandos de menu.

  • Criar manipulador separado de gesto e projetos de VSIX. Use este método se você desejar combinar vários tipos de extensões no mesmo VSIX. Por exemplo, se seu manipulador de gesto esperar que o modelo observe as restrições específicas, você poderá inseri-lo no mesmo VSIX que um método de validação.

Para criar um manipulador de gesto em seu próprio VSIX

  1. Na caixa de diálogo Novo Projeto, em Modelando Projetos, selecione Extensão de Gesto.

  2. Abra o arquivo .cs no novo projeto e modifique a classe GestureExtension para implementar o seu manipulador de gesto.

    Para obter mais informações, consulte Implementando o manipulador de gesto.

  3. Teste o manipulador de gesto pressionando F5. Para obter mais informações, consulte Executando o manipulador de gesto.

  4. Instale o manipulador de gesto em outro computador copiando o arquivo bin\*\*.vsix que é compilado pelo seu projeto. Para obter mais informações, consulte Instalando o manipulador de gesto.

Veja o procedimento alternativo:

Para criar um projeto de biblioteca de classe separada (DLL) para o manipulador de gesto

  1. Crie um projeto de biblioteca de classes, em uma solução nova ou existente do Visual Studio.

    1. No menu Arquivo, escolha Novo Projeto.

    2. Em Modelos Instalados, expanda Visual C# ou Visual Basic e, na coluna do meio, escolha Biblioteca de Classes.

  2. Adicione as seguintes referências ao projeto.

    Microsoft.VisualStudio.Modeling.Sdk.12.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.12.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

    System.Windows.Forms

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer – você precisa disso somente se você estiver estendendo diagramas de camada. Para obter mais informações, consulte Estendendo diagramas de camada.

  3. Adicione um arquivo de classe ao projeto e defina seu conteúdo para o código a seguir.

    Dica

    Altere o namespace e o nome da classe de acordo com sua preferência.

    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
    using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Uml.Classes;
    // ADD other UML namespaces if required
    
    namespace MyGestureHandler // CHANGE
    {
      // DELETE any of these attributes if the handler
      // should not work with some types of diagram.
      [ClassDesignerExtension]
      [ActivityDesignerExtension]
      [ComponentDesignerExtension]
      [SequenceDesignerExtension]
      [UseCaseDesignerExtension]
      // [LayerDesignerExtension]
    
      // Gesture handlers must export IGestureExtension:
      [Export(typeof(IGestureExtension))]
      // CHANGE class name
      public class MyGesture1 : IGestureExtension
      {
        [Import]
        public IDiagramContext DiagramContext { get; set; }
    
        /// <summary>
        /// Called when the user double-clicks on the diagram
        /// </summary>
        /// <param name="targetElement"></param>
        /// <param name="diagramPointEventArgs"></param>
        public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target shape, if any. Null if the target is the diagram.
          IShape targetIShape = targetElement.CreateIShape();
    
          // Do something...
        }
    
        /// <summary>
        /// Called repeatedly when the user drags from anywhere on the screen.
        /// Return value should indicate whether a drop here is allowed.
        /// </summary>
        /// <param name="targetMergeElement">References the element to be dropped on.</param>
        /// <param name="diagramDragEventArgs">References the element to be dropped.</param>
        /// <returns></returns>
        public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target element, if any. Null if the target is the diagram.
          IShape targetIShape = targetMergeElement.CreateIShape();
    
          // This example allows drag of any UML elements.
          return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0;
        }
    
    
        /// <summary>
        /// Execute the action to be performed on the drop.
        /// </summary>
        /// <param name="targetDropElement"></param>
        /// <param name="diagramDragEventArgs"></param>
        public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
        }
    
        /// <summary>
        /// Retrieves UML IElements from drag arguments.
        /// Works for drags from UML diagrams.
        /// </summary>
        private IEnumerable<IElement> GetModelElementsFromDragEvent
                (DiagramDragEventArgs dragEvent)
        {
          //ElementGroupPrototype is the container for
          //dragged and copied elements and toolbox items.
          ElementGroupPrototype prototype =
             dragEvent.Data.
             GetData(typeof(ElementGroupPrototype))
                  as ElementGroupPrototype;
          // Locate the originals in the implementation store.
          IElementDirectory implementationDirectory =
             dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
    
          return prototype.ProtoElements.Select(
            prototypeElement =>
            {
              ModelElement element = implementationDirectory
                .FindElement(prototypeElement.ElementId);
              ShapeElement shapeElement = element as ShapeElement;
              if (shapeElement != null)
              {
                // Dragged from a diagram.
                return shapeElement.ModelElement as IElement;
              }
              else
              {
                // Dragged from UML Model Explorer.
                return element as IElement;
              }
            });
        }
    
      }
    }
    

    Para obter mais informações sobre o que colocar nos métodos, consulte Implementando o manipulador de gesto.

Você deve adicionar o comando de menu a um projeto VSIX, que atua como um contêiner para instalação do comando. Se você desejar, você pode incluir outros componentes no mesmo VSIX.

Para adicionar um manipulador separado de gesto a um projeto VSIX

  1. Você não precisará deste procedimento se tiver criado o manipulador de gesto com seu próprio VSIX.

  2. Crie um projeto de VSIX, a menos que sua solução já tenha um.

    1. No Gerenciador de Soluções, no menu de atalho da solução, escolha Adicionar, Novo Projeto.

    2. Em Modelos Instalados, expanda Visual C# ou Visual Basic e selecione Extensibilidade. Na coluna do meio, escolha Projeto VSIX.

  3. Defina o projeto VSIX como o projeto de inicialização da solução.

    • No Gerenciador de Soluções, no menu de atalho do projeto VSIX, selecione Definir como projeto de inicialização.
  4. No source.extension.vsixmanifest, adicione o projeto de biblioteca de classe de manipulador de gesto como um componente de MEF:

    1. Na guia Metadados, defina um nome para o VSIX.

    2. Na guia Instalar Destinos, defina o Visual Studio Ultimate e Premium como os destinos.

    3. Na guia Ativos, escolha Novo e, na caixa de diálogo, defina:

      Digite = Componente MEF

      Origem = Um projeto na solução atual

      Projeto = Your class library project

Executando o manipulador do gesto

Para fins de teste, execute o manipulador de gesto em modo de depuração.

Para testar o manipulador de gesto

  1. Pressione F5 ou, no menu Depurar, clique em Iniciar Depuração.

    Uma instância experimental do Visual Studio é iniciada.

    Solução de problemas: se um novo Visual Studio não for iniciado:

    • Se você tiver mais de um projeto, certifique-se que o projeto de VSIX seja definido como projeto de inicialização da solução.

    • No Gerenciador de Soluções, no menu de atalho da inicialização ou somente projeto, escolha Propriedades. No editor de propriedades de projeto, escolha a guia Depurar. Certifique-se de que a cadeia de caracteres no campo de Iniciar programa externo seja o nome do caminho completo de Visual Studio, normalmente:

      C:\Arquivos de Programas\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe

  2. No Visual Studio experimental, abra ou crie um projeto de modelagem e abra ou crie um diagrama de modelagem. Use um diagrama que pertence a um dos tipos listados nos atributos de sua classe de manipulador de gesto.

  3. Clique duas vezes em qualquer lugar no diagrama. Seu manipulador de clique duplo deve ser chamado.

  4. Arraste um elemento do UML Explorer para o diagrama. Seu manipulador arrastar deve ser chamado.

Solução de problemas: se o manipulador de gesto não funcionar, verifique se:

  • O projeto do manipulador de gesto está listado como um componente MEF na guia Ativos em source.extensions.manifest no projeto VSIX.

  • Os parâmetros de todos os atributos Import e Export são válidos.

  • O método CanDragDrop não está retornando false.

  • O tipo de diagrama modelo que você está usando (classe UML, sequência, etc.) é listado como um dos atributos da classe de manipulador de gesto [ClassDesignerExtension], [SequenceDesignerExtension] e assim por diante.

  • Não há nenhuma funcionalidade interna já definida para esse tipo de destino e elemento solto.

Implementando o manipulador de gesto

Os métodos do manipulador de gesto

A classe manipulador de gesto implementa e exporta IGestureExtension. Os métodos que você precisa definir são:

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Retornar true para permitir que o elemento de origem referenciado em dragEvent seja solto nesse destino.

Esse método não deve fazer alterações no modelo. Deve trabalhar rapidamente, porque é usado para determinar o estado da seta quando o usuário move o mouse.

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

Atualize o modelo baseado no objeto de origem referenciado em dragEvent, e no destino.

Chamado quando o usuário libera o mouse após arrastar.

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target é a forma que o usuário clicou duas vezes.

Você pode escrever manipuladores que podem aceitar não apenas UML, mas também uma ampla variedade de outros itens, como arquivos, nós em um modo de exibição de classe. NET, nós do Gerenciador de Arquitetura e assim por diante. O usuário pode arrastar qualquer um desses itens para um diagrama UML, desde que você escreva um método OnDragDrop que possa decodificar o formulário serializado dos itens. Os métodos de decodificação variam de um tipo de item para outro.

Os parâmetros desses métodos são:

  • ShapeElement target. A forma ou o diagrama para o qual o usuário arrastou algo.

    ShapeElement é uma classe na implementação que serve de base para as ferramentas de modelagem de UML. Para reduzir o risco de colocar o modelo e os diagramas UML em um estado inconsistente, é recomendável não usar os métodos dessa classe diretamente. Em vez disso, coloque o elemento em IShape e, em seguida, use os métodos descritos em Como exibir um modelo em diagramas.

    • Para obter um IShape:

      IShape targetIShape = target.CreateIShape(target);
      
    • Para obter o elemento modelo que é visado pela operação arrastar ou clique duplo:

      IElement target = targetIShape.Element;
      

      Você pode converter isso em um tipo de elemento mais específico.

    • Para obter o armazenamento de modelo UML que contém o modelo UML:

      IModelStore modelStore = 
        targetIShape.Element.GetModelStore(); 
      
    • Para obter acesso ao host e ao provedor de serviços:

      target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
      
  • DiagramDragEventArgs eventArgs. Esse parâmetro carrega o formulário serializado do objeto de origem de uma operação arrastar:

    System.Windows.Forms.IDataObject data = eventArgs.Data;  
    

    Você pode arrastar elementos de vários tipos diferentes para um diagrama, de partes diferentes de Visual Studio, ou da área de trabalho do Windows. Os diferentes tipos de elemento são codificados de diferentes formas no IDataObject. Para extrair os elementos dele, consulte a documentação para o tipo apropriado de objeto.

    Se seu objeto fonte for um elemento de UML arrastado do gerenciador de modelos UML ou outro diagrama de UML, consulte Como obter elementos de modelo UML de IDataObject.

Escrevendo o código dos métodos

Para obter mais informações sobre como escrever o código para ler e atualizar o modelo, consulte Programando com a API UML.

Para obter informações sobre como acessar informações de modelo em uma operação de arrastar, consulte Como obter elementos de modelo UML de IDataObject.

Se você estiver lidando um diagrama de sequência, consulte também Como editar diagramas de sequência usando a API UML.

Além dos parâmetros dos métodos, você pode também declarar uma propriedade importada em sua classe que fornece acesso ao diagrama e modelo atuais.

[Import] public IDiagramContext DiagramContext { get; set; }

A declaração de IDiagramContext permite que você escreva códigos em seus métodos que acessam o diagrama, a seleção atual e o modelo:

IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}

Para obter mais informações, consulte Como: navegar no modelo UML.

Instalando e desinstalando uma extensão

Você pode instalar uma extensão de Visual Studio no seu próprio computador e em outros computadores.

Para instalar uma extensão

  1. No seu computador, localize o arquivo .vsix criado pelo seu projeto VSIX.

    1. No Gerenciador de Soluções, no menu de atalho do projeto de VSIX, escolha Abrir pasta no Windows Explorer.

    2. Localize o arquivo bin\*\YourProject.vsix

  2. Copie o arquivo de .vsix para o computador de destino em que você deseja instalar a extensão. Pode ser o seu próprio computador ou algum outro.

    O computador de destino deve ter uma das edições de Visual Studio que você especificou em source.extension.vsixmanifest.

  3. No computador de destino, abra o arquivo .vsix.

    Instalador de Extensão do Visual Studio abre e instala a extensão.

  4. Inicie ou reinicie o Visual Studio.

Para desinstalar uma extensão

  1. No menu de Ferramentas, escolha Gerenciador de Extensões.

  2. Expanda Extensões Instaladas.

  3. Selecione a extensão e escolha Desinstalar.

Raramente, uma extensão defeituosa falha ao ser carregada e cria um relatório na janela de erros, mas não aparece no Gerenciador de Extensões. Nesse caso, você pode remover a extensão excluindo o arquivo de:

%LocalAppData%\Local\Microsoft\VisualStudio\12.0\Extensions

Exemplo

O exemplo a seguir mostra como criar linhas de vida em um diagrama de sequência, com base nas partes e nas portas de um componente arrastadas de um diagrama componentes.

Para testá-lo, pressione F5. Uma instância experimental do Visual Studio abre. Nesse caso, abra um modelo de UML e crie um componente em um diagrama de componente. Adicione a este componente algumas interfaces e partes de componentes internos. Selecione as interfaces e as partes. Arraste as interfaces e partes para um diagrama de sequência. (Arraste do diagrama de componentes até a guia para o diagrama de sequência, em seguida, desça para dentro do diagrama de sequência). Uma linha de vida será exibida para cada interface e parte.

Para obter mais informações sobre iterações de associação para diagramas de sequência, consulte Como editar diagramas de sequência usando a API UML.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;

/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
  [Import]
  public IDiagramContext Context { get; set; }

  /// <summary>
  /// Called by the modeling framework when
  /// the user drops something on a target.
  /// </summary>
  /// <param name="target">The target shape or diagram </param>
  /// <param name="dragEvent">The item being dragged</param>
  public void OnDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    ISequenceDiagram diagram = Context.CurrentDiagram
            as ISequenceDiagram;
    IInteraction interaction = diagram.Interaction;
    if (interaction == null)
    {
      // Sequence diagram is empty: create an interaction.
      interaction = diagram.ModelStore.Root.CreateInteraction();
      interaction.Name = Context.CurrentDiagram.Name;
      diagram.Bind(interaction);
    }
    foreach (IConnectableElement connectable in
       GetConnectablesFromDrag(dragEvent))
    {
      ILifeline lifeline = interaction.CreateLifeline();
      lifeline.Represents = connectable;
      lifeline.Name = connectable.Name;
    }
  }

  /// <summary>
  /// Called by the modeling framework to determine whether
  /// the user can drop something on a target.
  /// Must not change anything.
  /// </summary>
  /// <param name="target">The target shape or diagram</param>
  /// <param name="dragEvent">The item being dragged</param>
  /// <returns>true if this item can be dropped on this target</returns>
  public bool CanDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
    return connectables.Count() > 0;
  }

  ///<summary>
  /// Get dragged parts and ports of an IComponent.
  ///</summary>
  private IEnumerable<IConnectableElement>
    GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
  {
    foreach (IElement element in
      GetModelElementsFromDragEvent(dragEvent))
    {
      IConnectableElement part = element as IConnectableElement;
      if (part != null)
      {
        yield return part;
      }
    }
  }

  /// <summary>
  /// Retrieves UML IElements from drag arguments.
  /// Works for drags from UML diagrams.
  /// </summary>
  private IEnumerable<IElement> GetModelElementsFromDragEvent
          (DiagramDragEventArgs dragEvent)
  {
    //ElementGroupPrototype is the container for
    //dragged and copied elements and toolbox items.
    ElementGroupPrototype prototype =
       dragEvent.Data.
       GetData(typeof(ElementGroupPrototype))
            as ElementGroupPrototype;
    // Locate the originals in the implementation store.
    IElementDirectory implementationDirectory =
       dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;

    return prototype.ProtoElements.Select(
      prototypeElement =>
      {
        ModelElement element = implementationDirectory
          .FindElement(prototypeElement.ElementId);
        ShapeElement shapeElement = element as ShapeElement;
        if (shapeElement != null)
        {
          // Dragged from a diagram.
          return shapeElement.ModelElement as IElement;
        }
        else
        {
          // Dragged from UML Model Explorer.
          return element as IElement;
        }
      });
  }

  public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
  {
  }
}

O código de GetModelElementsFromDragEvent() é descrito em Como obter elementos de modelo UML de IDataObject.

Consulte também

Conceitos

Como definir e instalar uma extensão de modelagem

Estendendo modelos e diagramas UML

Como definir um comando de menu em um diagrama de modelagem

Como definir restrições de validação para modelos UML

Programando com a API UML