Compartilhar via


Personalizando a criação e o movimento de elementos

Você pode permitir que um elemento seja arrastado para outro, seja na caixa de ferramentas ou em uma operação de colar ou movimentar. Você pode ter os elementos movidos vinculados aos elementos de destino, usando as relações especificadas.

Uma diretiva de mesclagem de elementos (EMD) especifica o que acontece quando um elemento de modelo é mesclado em outro elemento de modelo. Isso ocorre quando:

  • O usuário arrasta da caixa de ferramentas para o diagrama ou uma forma.

  • O usuário cria um elemento usando um menu Adicionar no gerenciador ou em uma forma de compartimento.

  • O usuário move um item de uma raia para outra.

  • O usuário cola um elemento.

  • O código do programa chama a diretiva de mesclagem de elementos.

Embora as operações de criação possam parecer diferentes das operações de cópia, elas realmente funcionam da mesma maneira. Quando um elemento é adicionado, por exemplo, da caixa de ferramentas, um protótipo dele é replicado. O protótipo é mesclado no modelo da mesma maneira que os elementos que foram copiados de outra parte do modelo.

A responsabilidade de um EMD é decidir como um objeto ou grupo de objetos deve ser mesclado em um local específico no modelo. Em particular, ele decide quais relações devem ser instanciadas para vincular o grupo mesclado ao modelo. Você também pode personalizá-lo para definir propriedades e criar objetos adicionais.

Diagram showing a before and after look at a tree of elements and their reference relationships when An E M D determines how a new element is added.

Um EMD é gerado automaticamente quando você define um relacionamento de incorporação. Esse EMD padrão cria uma instância da relação quando os usuários adicionam novas instâncias filho ao pai. Você pode modificar esses EMDs padrão, por exemplo, adicionando código personalizado.

Você também pode adicionar seus próprios EMDs na definição de DSL para permitir que os usuários arrastem ou colem diferentes combinações de classes mescladas e de recebimento.

Definindo uma diretiva de mesclagem de elementos

Você pode adicionar diretivas de mesclagem de elementos a classes de domínio, relacionamentos de domínio, formas, conectores e diagramas. Você pode adicioná-los ou encontrá-los no Gerenciador de DSL na classe de domínio de recebimento. A classe de recebimento é a classe de domínio do elemento que já está no modelo e na qual o elemento novo ou copiado será mesclado.

Screenshot of DSL Explorer showing an E M D being added with ExampleElement selected as the Indexing class and the Applies to subclasses option checked.

A classe Indexação é a classe de domínio de elementos que podem ser mesclados em membros da classe de recebimento. Instâncias de subclasses da classe Indexação também serão mescladas por esse EMD, a menos que você defina Aplica-se a subclasses como Falso.

Há dois tipos de diretivas de mesclagem:

  • Uma diretiva Mesclagem de processo especifica as relações pelas quais o novo elemento deve ser vinculado à árvore.

  • Uma diretiva Encaminhar mesclagem redireciona o novo elemento para outro elemento de recebimento, normalmente um pai.

Você pode adicionar código personalizado para diretivas de mesclagem:

  • Definir Usa aceitação personalizada para adicionar seu próprio código para determinar se uma instância específica do elemento de indexação deve ser mesclada ao elemento de destino. Quando o usuário arrasta da caixa de ferramentas, o ponteiro "inválido" mostra se seu código não permite a mesclagem.

    Por exemplo, você pode permitir a mesclagem somente quando o elemento de recebimento estiver em um estado específico.

  • Definir Usa mesclagem personalizada para adicionar fornecimento de código próprio para definir as alterações feitas no modelo quando a mesclagem é executada.

    Por exemplo, você pode definir propriedades no elemento mesclado usando dados de seu novo local no modelo.

Observação

Se você gravar o código de mesclagem personalizado, ele afetará apenas mesclagens executadas usando esse EMD. Se houver outros EMDs que mesclem o mesmo tipo de objeto, ou se houver outro código personalizado que crie esses objetos sem usar o EMD, eles não serão afetados pelo seu código de mesclagem personalizado.

Se você quiser garantir que um novo elemento ou nova relação seja sempre processada pelo seu código personalizado, considere definir um AddRule no relacionamento de incorporação e um DeleteRule na classe de domínio do elemento. Para obter mais informações, consulte Regras propagam alterações no modelo.

Exemplo: definindo um EMD sem código personalizado

O exemplo a seguir permite que os usuários criem um elemento e um conector ao mesmo tempo arrastando da caixa de ferramentas para uma forma existente. O exemplo adiciona um EMD à Definição de DSL. Antes dessa modificação, os usuários podem arrastar ferramentas para o diagrama, mas não para formas existentes.

Os usuários também podem colar elementos em outros elementos.

Para permitir que os usuários criem um elemento e um conector ao mesmo tempo

  1. Crie uma DSL usando o modelo de solução Linguagem Mínima.

    Quando você executa essa DSL, ela permite criar formas e conectores entre as formas. Não é possível arrastar uma nova forma ExampleElement da caixa de ferramentas para uma forma existente.

  2. Para permitir que os usuários mesclem elementos em formas ExampleElement, crie um novo EMD na classe de domínio ExampleElement:

    1. No Gerenciador de DSL, expanda Classes de Domínio. Clique com o botão direito do mouse ExampleElement e clique em Adicionar Nova Diretiva de Mesclagem de Elementos.

    2. Verifique se a janela Detalhes da DSL está aberta para que você possa ver os detalhes do novo EMD. (Menu: Exibir, Outras Janelas, Detalhes de DSL.)

  3. Defina a classe Indexação na janela Detalhes da DSL para definir qual classe de elementos pode ser mesclada em objetos ExampleElement.

    Para esse exemplo, selecione ExampleElements para que o usuário possa arrastar novos elementos em elementos existentes.

    Observe que a classe Indexação se torna o nome do EMD no Gerenciador de DSL.

  4. Em Processar mesclagem criando links, adicione dois caminhos:

    • Um caminho vincula o novo elemento ao modelo pai. A expressão de caminho que você precisa inserir navega do elemento existente até o relacionamento de incorporação com o modelo pai. Por fim, ele especifica a função no novo link ao qual o novo elemento será atribuído. O caminho é o seguinte:

      ExampleModelHasElements.ExampleModel/!ExampleModel/.Elements

    • O outro caminho vincula o novo elemento ao elemento existente. A expressão de caminho especifica a relação de referência e a função à qual o novo elemento será atribuído. Esse caminho é o seguinte:

      ExampleElementReferencesTargets.Sources

      Você pode usar a ferramenta de navegação de caminho para criar cada caminho:

      1. Em Processar mesclagem criando links em caminhos, clique em <adicionar caminho>.

      2. Clique na seta suspensa à direita do item da lista. Um modo de exibição de árvore é mostrado.

      3. Expanda os nós na árvore para formar o caminho que você deseja especificar.

  5. Testar a DSL:

    1. Pressione F5 para recompilar e executar a solução.

      A recompilação levará mais tempo do que o normal porque o código gerado será atualizado a partir de modelos de texto para estar em conformidade com a nova Definição da DSL.

    2. Quando a instância experimental do Visual Studio for iniciada, abra um arquivo de modelo da sua DSL. Crie alguns elementos de exemplo.

    3. Arraste da ferramenta Elemento de Exemplo para uma forma existente.

      Uma nova forma é exibida e está vinculada à forma existente com um conector.

    4. Copie uma forma existente. Selecione outra forma e cole.

      Uma cópia da primeira forma é criada. Ela tem um novo nome e está vinculada à segunda forma com um conector.

Observe os seguintes pontos deste procedimento:

  • Ao criar diretivas de mesclagem de elementos, você pode permitir que qualquer classe de elemento aceite qualquer outra. O EMD é criado na classe de domínio de recebimento e a classe de domínio aceita é especificada no campo classe Índice.

  • Ao definir caminhos, você pode especificar quais links devem ser usados para conectar o novo elemento ao modelo existente.

    Os links especificados devem incluir um relacionamento de incorporação.

  • O EMD afeta a criação a partir da caixa de ferramentas e também as operações de colagem.

    Se você gravar o código personalizado que cria novos elementos, poderá invocar explicitamente o EMD usando o método ElementOperations.Merge. Isso garante que seu código vincule novos elementos ao modelo da mesma forma que outras operações. Para obter mais informações, consulte Personalizando o comportamento da cópia.

Exemplo: adicionando o Código aceitação personalizada a um EMD

Ao adicionar o código personalizado a um EMD, você pode definir um comportamento de mesclagem mais complexo. Esse exemplo simples impede que o usuário adicione mais do que um número fixo de elementos ao diagrama. O exemplo modifica o EMD padrão que acompanha um relacionamento de incorporação.

Para gravar o Código de aceitação personalizada para restringir o que o usuário pode adicionar

  1. Crie uma DSL usando o modelo de solução Linguagem Mínima. Abra o diagrama de Definição da DSL.

  2. No Gerenciador de DSL, expanda Classes de Domínio, ExampleModel, Diretivas de mesclagem de elementos. Selecione a diretiva de mesclagem de elementos chamada ExampleElement.

    Esse EMD controla como o usuário pode criar novos objetos ExampleElement no modelo, por exemplo, arrastando da caixa de ferramentas.

  3. Na janela Detalhes da DSL, selecione Usa aceitação personalizada.

  4. Recriar a solução. Isso levará mais tempo do que o normal porque o código gerado será atualizado a partir do modelo.

    Um erro de build será relatado, semelhante a: "Company.ElementMergeSample.ExampleElement não contém uma definição para CanMergeExampleElement..."

    Você deve implementar o método CanMergeExampleElement.

  5. Crie um novo arquivo de código no projeto DSL. Substitua seu conteúdo pelo código a seguir e altere o namespace para o namespace do seu projeto.

    using Microsoft.VisualStudio.Modeling;
    
    namespace Company.ElementMergeSample // EDIT.
    {
      partial class ExampleModel
      {
        /// <summary>
        /// Called whenever an ExampleElement is to be merged into this ExampleModel.
        /// This happens when the user pastes an ExampleElement
        /// or drags from the toolbox.
        /// Determines whether the merge is allowed.
        /// </summary>
        /// <param name="rootElement">The root element in the merging EGP.</param>
        /// <param name="elementGroupPrototype">The EGP that the user wants to merge.</param>
        /// <returns>True if the merge is allowed</returns>
        private bool CanMergeExampleElement(ProtoElementBase rootElement, ElementGroupPrototype elementGroupPrototype)
        {
          // Allow no more than 4 elements to be added:
          return this.Elements.Count < 4;
        }
      }
    }
    

    Esse exemplo simples restringe o número de elementos que podem ser mesclados ao modelo pai. Para condições mais interessantes, o método pode inspecionar qualquer uma das propriedades e links do objeto de recebimento. Ele também pode inspecionar as propriedades dos elementos de mesclagem, que são transportados em um ElementGroupPrototype. Para obter mais informações sobre ElementGroupPrototypes, consulte Personalizando o comportamento da cópia. Para obter mais informações sobre como gravar o código que lê um modelo, consulte Navegando e atualizando um modelo no código do programa.

  6. Testar a DSL:

    1. Pressione F5 para recompilar a solução. Quando a instância experimental do Visual Studio for aberta, abra uma instância da sua DSL.

    2. Crie novos elementos de várias maneiras:

      • Arraste da ferramenta Elemento de Exemplo para o diagrama.

      • No Gerenciador de Modelos de Exemplo, clique com o botão direito do mouse no nó raiz e clique em Adicionar Novo Elemento de Exemplo.

      • Copie e cole um elemento no diagrama.

    3. Verifique se você não pode usar nenhuma dessas maneiras para adicionar mais de quatro elementos ao modelo. Isso ocorre porque todas elas usam a Diretiva de Mesclagem de Elementos.

Exemplo: adicionando o Código de mesclagem personalizada a um EMD

No código de mesclagem personalizada, você pode definir o que acontece quando o usuário arrasta uma ferramenta ou cola em um elemento. Há duas maneiras de definir uma mesclagem personalizada:

  1. Defina Usa Mesclagem Personalizada e forneça o código necessário. Seu código substitui o código de mesclagem gerado. Use essa opção se quiser redefinir completamente o que a mesclagem faz.

  2. Substitua o método MergeRelate e, opcionalmente, o método MergeDisconnect. Para fazer isso, você deve definir a propriedade Gera Derivação Dupla da classe de domínio. Seu código pode chamar o código de mesclagem gerado na classe base. Use essa opção se quiser executar operações adicionais após a mesclagem ter sido executada.

    Essas abordagens afetam apenas mesclagens executadas usando esse EMD. Se você quiser afetar todas as maneiras pelas quais o elemento mesclado pode ser criado, uma alternativa é definir um AddRule no relacionamento de incorporação e um DeleteRule na classe de domínio mesclada. Para obter mais informações, consulte Regras propagam alterações no modelo.

Para substituir MergeRelate

  1. Na definição da DSL, verifique se você definiu o EMD ao qual deseja adicionar o código. Se desejar, você pode adicionar caminhos e definir o código de aceitação personalizado, conforme descrito nas seções anteriores.

  2. No diagrama DslDefinition, selecione a classe de recebimento da mesclagem. Normalmente, é a classe na extremidade fonte de um relacionamento de incorporação.

    Por exemplo, em uma DSL gerada a partir da solução Linguagem Mínima, selecione ExampleModel.

  3. Na janela Propriedades, defina Gera Derivação Dupla como true.

  4. Recriar a solução.

  5. Inspecione o conteúdo de Dsl\Generated Files\DomainClasses.cs. Pesquise métodos chamados MergeRelate e examine seus conteúdos. Isso ajudará você a gravar suas próprias versões.

  6. Em um novo arquivo de código, grave uma classe parcial para a classe de recebimento e substitua o método MergeRelate. Lembre-se de chamar o método base. Por exemplo:

    partial class ExampleModel
    {
      /// <summary>
      /// Called when the user drags or pastes an ExampleElement onto the diagram.
      /// Sets the time of day as the name.
      /// </summary>
      /// <param name="sourceElement">Element to be added</param>
      /// <param name="elementGroup">Elements to be merged</param>
      protected override void MergeRelate(ModelElement sourceElement, ElementGroup elementGroup)
      {
        // Connect the element according to the EMD:
        base.MergeRelate(sourceElement, elementGroup);
    
        // Custom actions:
        ExampleElement mergingElement = sourceElement as ExampleElement;
        if (mergingElement != null)
        {
          mergingElement.Name = DateTime.Now.ToLongTimeString();
        }
      }
    }
    

Para gravar o Código de mesclagem personalizada

  1. Em Dsl\Generated Code\DomainClasses.cs, inspecione métodos chamados MergeRelate. Esses métodos criam links entre um novo elemento e o modelo existente.

    Além disso, inspecione métodos chamados MergeDisconnect. Esses métodos desvinculam um elemento do modelo quando ele deve ser excluído.

  2. No Gerenciador da DSL, selecione ou crie a Diretiva de Mesclagem de Elementos que você deseja personalizar. Na janela Detalhes da DSL, defina Usa Mesclagem Personalizada.

    Quando você define essa opção, as opções Mesclagem de Processo e Encaminhar Mesclagem são ignoradas. Em vez disso, seu código é usado.

  3. Recriar a solução. Isso levará mais tempo do que o normal porque os arquivos do código gerado serão atualizados a partir do modelo.

    As mensagens de erro serão exibidas. Clique duas vezes nas mensagens de erro para ver as instruções no código gerado. Essas instruções solicitam que você forneça dois métodos, MergeRelateYourDomainClass e MergeDisconnectYourDomainClass

  4. Grave os métodos em uma definição de classe parcial em um arquivo de código separado. Os exemplos que você inspecionou anteriormente devem sugerir o que você precisa.

    O código de mesclagem personalizado não afetará o código que cria objetos e relações diretamente e não afetará outros EMDs. Para garantir que suas alterações adicionais sejam implementadas independentemente de como o elemento é criado, considere gravar um AddRule e um DeleteRule. Para obter mais informações, consulte Regras propagam alterações no modelo.

Redirecionando uma operação de mesclagem

Um Encaminhar diretiva de mesclagem redireciona o destino de uma operação de mesclagem. Normalmente, o novo destino é o pai da inserção do destino inicial.

Por exemplo, em uma DSL criada com o modelo de diagrama de componente, as portas são inseridas em Componentes. As portas são exibidas como pequenas formas na borda de uma forma Componente. O usuário cria portas arrastando a ferramenta Porta para uma forma Componente. Mas, às vezes, o usuário arrasta erroneamente a ferramenta Porta para uma porta existente, em vez do componente, e a operação falha. Esse é um erro fácil quando há várias portas existentes. Para ajudar o usuário a evitar esse incômodo, você pode permitir que as portas sejam arrastadas para uma porta existente, mas faça com que a ação seja redirecionada para o componente pai. A operação funciona como se o elemento de destino fosse o componente.

Você pode criar um Encaminhar diretiva de mesclagem na solução Modelo de Componente. Se você compilar e executar a solução original, verá que os usuários podem arrastar qualquer número de elementos de Porta de Entrada ou Porta de Saída da Caixa de Ferramentas para um elemento Component. No entanto, eles não podem arrastar uma porta para uma porta existente. O ponteiro Indisponível alerta que essa movimentação não está habilitada. No entanto, você pode criar um Encaminhar diretiva de mesclagem para que uma porta que seja removida involuntariamente em uma Porta de Entrada existente seja encaminhada para o elemento Componente.

Para criar um Encaminhar diretiva de mesclagem

  1. Crie uma solução Ferramentas de Linguagem Específica de Domínio usando o modelo Modelo de Componente.

  2. Exiba o Gerenciador da DSL abrindo DslDefinition.dsl.

  3. No Gerenciador da DSL, expanda Classes de Domínio.

  4. A classe de domínio abstrata ComponentPort é a classe base de InPort e OutPort. Clique com o botão direito do mouse ComponentPorte depois clique em Adicionar Nova Diretiva de Mesclagem de Elementos.

    Um novo nó Diretiva de Mesclagem de Elementos aparece no nó Diretivas de Mesclagem de Elementos.

  5. Selecione o nó Diretiva de Mesclagem de Elementos e abra a janela Detalhes da DSL.

  6. Na lista da classe Indexação, selecione ComponentPort.

  7. Selecione Encaminhar mesclagem para uma classe de domínio diferente.

  8. Na lista de seleção do caminho, expanda ComponentPort, expanda ComponentHasPorts e, em seguida, selecione Componente.

    O novo caminho deve ser semelhante a este:

    ComponentHasPorts.Component/!Component

  9. Salve a solução e transforme os modelos clicando no botão mais à direita na barra de ferramentas Gerenciador de Soluções.

  10. Compile e execute a solução. Uma nova instância do Visual Studio é exibida.

  11. Em Gerenciador de Soluções, abra Sample.mydsl. O diagrama e a Caixa de Ferramentas ComponentLanguage são exibidos.

  12. Arraste uma Porta de Entrada da Caixa de Ferramentas para outra Porta de Entrada. Em seguida, arraste um OutputPort para um InputPort e, em seguida, para outro OutputPort.

    Você não deve ver o ponteiro Indisponível e deve ser capaz de remover a nova Porta de Entrada na porta existente. Selecione a nova Porta de Entrada e arraste-a para outro ponto no Componente.