Compartir a través de


Cómo: Modificar diagramas de secuencia usando la API de UML

Una interacción es una secuencia de mensajes entre un conjunto de líneas de vida. Las interacciones se muestran en un diagrama de secuencia.

Para obtener todos los detalles sobre la API, vea Microsoft.VisualStudio.Uml.Interactions.

Para obtener una introducción más general a la escritura de comandos y controladores de gestos para diagramas UML, vea Cómo: Definir un comando de menú en un diagrama de modelado.

Código básico

Importaciones del espacio de nombres

Debe incluir las siguientes instrucciones using:

using Microsoft.VisualStudio.Uml.Classes;
   // for basic UML types such as IPackage
using Microsoft.VisualStudio.Uml.Interactions;
   // for interaction types
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
   // to create elements and use additional functions

Si está creando comandos de menú y controladores de gestos, también necesitará:

using System.ComponentModel.Composition; 
   // for Import and Export
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
   // for ICommandExtension
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
   // for diagrams and context

Para obtener más información, vea Cómo: Definir un comando de menú en un diagrama de modelado.

Obtener el contexto

Si está editando una interacción que forma parte de un controlador de comandos o gestos en un diagrama de secuencia, puede obtener una referencia al contexto. Por ejemplo:

    [SequenceDesignerExtension]
    [Export(typeof(ICommandExtension))]  
    public class MySequenceDiagramCommand : ICommandExtension
    {
        [Import]
        public IDiagramContext Context { get; set; }
        public void QueryStatus (IMenuCommand command)
        {
          ISequenceDiagram sequenceDiagram = 
              Context.CurrentDiagram as ISequenceDiagram;
             ...

Diagramas de secuencia de UML y generados

Existen dos tipos de diagramas de secuencia: aquellos que se crean manualmente en un proyecto de modelado de UML y aquellos que se generan desde el código del programa. Puede utilizar la propiedad UmlMode para detectar con qué tipo de diagrama de secuencia está trabajando.

Por ejemplo, si desea crear un comando de menú que solo esté visible en diagramas de secuencia UML, el método QueryStatus() podría incluir la siguiente instrucción:

    command.Enabled = command.Visible = 
          sequenceDiagram != null && sequenceDiagram.UmlMode;

En un diagrama de secuencia generado, las líneas de vida, mensajes y otros elementos son muy similares a los de un diagrama de secuencia UML. En un modelo UML, el Almacén de modelos tiene una raíz, que es el Modelo que posee todos los demás elementos; pero existe una interacción generada en su propio Almacén de modelos, que tiene una raíz nula:

    IModel rootModel = sequenceDiagram.ModelStore.Root;
    // !sequenceDiagram.UmlMode == (rootModel == null)

Para crear y mostrar una interacción

Cree la interacción como un elemento secundario de un paquete o modelo.

Por ejemplo, si está desarrollando un comando que se podría ejecutar en un diagrama de secuencia vacío, siempre debería comenzar comprobando si existe la interacción.

public void Execute (IMenuCommand command)
{
    ISequenceDiagram sequenceDiagram = 
         Context.CurrentDiagram as ISequenceDiagram;
    if (sequenceDiagram == null) return;
    // Get the diagram's interaction:
    IInteraction interaction = sequenceDiagram.Interaction;
    // A new sequence diagram might have no interaction:
    if (interaction == null)
    {
       // Get the home package or model of the diagram:
       IPackage parentPackage = sequenceDiagram.GetObject<IPackage>();
       interaction = parentPackage.CreateInteraction();
       // Display the interaction on the sequence diagram:
       sequenceDiagram.Bind(interaction);
    } 

Actualizar una interacción y su diseño

Al actualizar una Interacción, finalice siempre la operación actualizando su diseño mediante uno de los siguientes métodos:

  • ISequenceDiagram.UpdateShapePositions() ajusta las posiciones de las formas que se han insertado o movido recientemente y sus formas vecinas.

  • ISequenceDiagram.Layout([SequenceDiagramLayoutKinds]) dibuja de nuevo todo el diagrama. Puede utilizar el parámetro para especificar el cambio de posición de las líneas de vida, los mensajes o ambos.

Esto es particularmente importante al insertar nuevos elementos o mover los elementos existentes. No estarán en las posiciones correctas en el diagrama hasta que haya realizado una de estas operaciones. Solo necesita llamar una vez a una de estas operaciones al final de una serie de cambios.

Para no confundir al usuario que realiza una fase de reversión después de su comando, utilice ILinkedUndoTransaction para agregar sus cambios y las operaciones Layout() o UpdateShapePositions() finales. Por ejemplo:

using (ILinkedUndoTransaction transaction = LinkedUndoContext.BeginTransaction("create loop"))
{
  Interaction.CreateCombinedFragment(InteractionOperatorKind.Loop, messages);
  Diagram.UpdateShapePositions();
  transaction.Commit();
}

Para utilizar una ILinkedUndoTransaction, debe realizar esta declaración en su clase:

[Import] ILinkedUndoContext LinkedUndoContext { get; set; }

Para obtener más información, vea Cómo: Vincular actualizaciones del modelo mediante transacciones.

Compilar una interacción

Para crear líneas de vida

ILifeline lifeline = interaction.CreateLifeline();

Una línea de vida representa un elemento que se puede conectar, es decir, una instancia de un tipo. Por ejemplo, si la interacción se utiliza para mostrar cómo un componente delega los mensajes entrantes en sus elementos internos, las líneas de vida pueden representar los puertos y elementos del componente:

foreach (IConnectableElement part in 
            component.Parts
           .Concat<IConnectableElement>(component.OwnedPorts))
{
   ILifeline lifeline = interaction.CreateLifeline();
   lifeline.Represents = part;
}

Por otro lado, si en la interacción se muestra un conjunto arbitrario de objetos, puede crear una propiedad u otro objeto IConnectableElement en la propia interacción:

ILifeline lifeline = interaction.CreateLifeline();
IProperty property1 = interaction.CreateProperty();
property1.Type = model.CreateInterface();
property1.Type.Name = "Type 1";
lifeline.Represents = property1;

Otra alternativa consiste en establecer el nombre y tipo de una línea de vida sin vincularla a un elemento conectable:

ILifeline lifeline = interaction.CreateLifeline();
lifeline.Name = "c1";
lifeline.SetInstanceType("Customer");
System.Diagnostics.Debug.Assert(
           lifeline.GetDisplayName() == "c1:Customer"  );

Para crear mensajes

Para crear un mensaje, debe identificar los puntos de inserción en las líneas de vida de origen y destino. Por ejemplo:

interaction.CreateMessage( sourceInsertionPoint, 
                           targetInsertionPoint, 
                           MessageKind.Complete, 
                           MessageSort.ASynchCall)

Para crear un mensaje que tenga un origen y un destino que no estén definidos:

interaction.CreateLostFoundMessage(MessageKind.Found, insertionPoint);

Hay varios mensajes que se pueden utilizar para identificar los puntos de inserción de todos los puntos clave de una línea de vida:

Método de ILifeline

Utilícelo para insertar en este punto

FindInsertionPointAtTop()

La parte superior de la línea de vida.

FindInsertionPointAtBottom()

La parte inferior de la línea de vida.

FindInsertionPointAfterMessage

(IMessage previous)

Un punto inmediatamente posterior al mensaje especificado.

FindInsertionPointAfterExecutionSpecification

(IExecutionSpecification previous)

El punto puede estar en la línea de vida o en un bloque de especificación de ejecución primario.

FindInsertionPointAfterInteractionUse

(IInteractionUse previous)

Un punto que siga a un uso de interacción.

FindInsertionPointAfterCombinedFragment

(ICombinedFragment previous)

Un punto que siga a un fragmento combinado.

FindInsertionPoint(IExecutionSpecification block)

La parte superior de un bloque de ejecución.

FindInsertionPoint(IInteractionOperand fragment)

La parte superior de un operando de un fragmento combinado.

Al crear mensajes, tenga cuidado de no definir un mensaje que atraviese otro mensaje.

Para crear fragmentos combinados y usos de la interacción

Puede crear fragmentos combinados y Usos de la interacción especificando un punto de inserción en cada línea de vida que debe cubrir el elemento. Tenga cuidado de no especificar un conjunto de puntos que atraviesen un mensaje o fragmento existente.

Interaction.CreateCombinedFragment(InteractionOperatorKind.Loop, 
  Interaction.Lifelines.Select(lifeline => lifeline.FindInsertionPointAtTop()));
Interaction.CreateInteractionUse(
  Interaction.Lifelines.Select(lifeline => lifeline.FindInsertionPointAtTop()));

También puede crear un fragmento combinado que cubra un conjunto de mensajes existente. Todos los mensajes se deben tener su origen en la misma línea de vida o bloque de ejecución.

ICombinedFragment cf = Interaction.CreateCombinedFragment(
  InteractionOperatorKind.Loop,
  Interaction.Lifelines.First().GetAllOutgoingMessages());

Un fragmento combinado siempre se crea con un único operando. Para crear un nuevo operando, debe especificar un operando existente, y si desea insertar el nuevo operando antes o después de él:

// Create an additional operand before the first
cf.CreateInteractionOperand(cf.Operands.First(), false);
// Create an additional operand after the last:
cf.CreateInteractionOperand(cf.Operands.Last(), true);

Solución de problemas

Las formas aparecerán en posiciones incorrectas si los cambios no se completan con una operación UpdateShapePositions() o Layout().

La mayoría de los demás problemas se producen por puntos de inserción desalineados, que hacen que los nuevos mensajes o fragmentos atraviesan otros. Los síntomas pueden ser que no sea posible realizar ningún cambio, o se produzca una excepción. La excepción podría no producirse hasta que se realice la operación UpdateShapePositions() o Layout().

Vea también

Referencia

Microsoft.VisualStudio.Uml.Interactions

Otros recursos

Ampliar modelos y diagramas UML

Cómo: Definir un comando de menú en un diagrama de modelado

Cómo: Definir un elemento personalizado en un cuadro de herramientas de modelado

Cómo: Definir restricciones de validación para modelos UML

Programar con la API de UML