Procedura: modificare i diagrammi di sequenza tramite l'API UML
Un'interazione è una sequenza di messaggi tra un set di linee di vita.Un'interazione viene visualizzata in un diagramma di sequenza.
Per informazioni dettagliate sull'API, vedere Microsoft.VisualStudio.Uml.Interactions.
Per un'introduzione più generale alla scrittura di comandi e gestori movimenti per i diagrammi UML, vedere Procedura: definire un comando di menu in un diagramma di modellazione.
Codice di base
Importazioni degli spazi dei nomi
È necessario includere le istruzioni using seguenti:
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
Se si creano comandi di menu e gestori movimenti, sarà inoltre necessario:
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
Per ulteriori informazioni, vedere Procedura: definire un comando di menu in un diagramma di modellazione.
Recupero del contesto
Se si modifica un'interazione come parte di un gestore comandi o movimenti in un diagramma sequenza, è possibile ottenere un riferimento al contesto.Ad esempio:
[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;
...
Diagrammi di sequenza UML e generati
Esistono due tipi di diagrammi di sequenza: quelli che vengono creati manualmente in un progetto di modello UML e quelli che vengono generati dal codice programma.È possibile utilizzare la proprietà UmlMode per individuare il tipo di diagramma sequenza utilizzato.
Ad esempio, se si desidera creare un comando di menu che sia visibile unicamente in diagrammi sequenza UML, il metodo QueryStatus() potrebbe includere l'istruzione seguente:
command.Enabled = command.Visible =
sequenceDiagram != null && sequenceDiagram.UmlMode;
In un diagramma sequenza generato, le linee di vita, i messaggi e altri elementi sono pressoché uguali a quelli presenti in un diagramma sequenza UML.In un modello UML l'archivio modelli dispone di una radice data dal modello proprietario di tutti gli altri elementi, tuttavia un'interazione generata esiste in un proprio archivio modelli che dispone di una radice null:
IModel rootModel = sequenceDiagram.ModelStore.Root;
// !sequenceDiagram.UmlMode == (rootModel == null)
Per creare e visualizzare un'interazione
Creare l'interazione come elemento figlio di un pacchetto o di un modello.
Ad esempio, se si sviluppa un comando che potrebbe essere eseguito in un diagramma sequenza vuoto, è innanzitutto necessario verificare che l'interazione esista.
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);
}
Aggiornamento di un'interazione e del relativo layout
Quando si aggiorna un'interazione, terminare sempre l'operazione aggiornando il relativo layout utilizzando uno dei metodi seguenti:
ISequenceDiagram.UpdateShapePositions() regola le posizioni delle forme che sono state recentemente inserite o spostate e le forme adiacenti.
ISequenceDiagram.Layout([SequenceDiagramLayoutKinds]) ridisegna l'intero diagramma.È possibile utilizzare il parametro per specificare il riposizionamento delle linee di vita, dei messaggi o di entrambi.
Questo è particolarmente importante quando si inseriscono nuovi elementi o si spostano elementi esistenti.Non si troveranno nelle posizioni corrette nel diagramma finché non verrà eseguita una di queste operazioni.È sufficiente chiamare una di queste operazioni alla fine di una serie di modifiche.
Per evitare di confondere l'utente che esegue un'operazione di annullamento dopo il comando, utilizzare ILinkedUndoTransaction per racchiudere le modifiche e le operazioni Layout() o UpdateShapePositions() finali.Ad esempio:
using (ILinkedUndoTransaction transaction = LinkedUndoContext.BeginTransaction("create loop"))
{
Interaction.CreateCombinedFragment(InteractionOperatorKind.Loop, messages);
Diagram.UpdateShapePositions();
transaction.Commit();
}
Per utilizzare ILinkedUndoTransaction, è necessario eseguire questa dichiarazione nella classe:
[Import] ILinkedUndoContext LinkedUndoContext { get; set; }
Per ulteriori informazioni, vedere Procedura: collegare aggiornamenti di modelli tramite transazioni.
Compilazione di un'interazione
Per creare linee di vita
ILifeline lifeline = interaction.CreateLifeline();
Una linea di vita rappresenta un elemento collegabile, ovvero un'istanza di un tipo.Se ad esempio l'interazione viene utilizzata per illustrare il modo in cui un componente delega i messaggi in arrivo alle relative parti interne, le linee di vita possono rappresentare le porte e le parti del componente:
foreach (IConnectableElement part in
component.Parts
.Concat<IConnectableElement>(component.OwnedPorts))
{
ILifeline lifeline = interaction.CreateLifeline();
lifeline.Represents = part;
}
In alternativa, se l'interazione mostra un set arbitrario di oggetti, è possibile creare una proprietà o un altro oggetto IConnectableElement nell'interazione stessa:
ILifeline lifeline = interaction.CreateLifeline();
IProperty property1 = interaction.CreateProperty();
property1.Type = model.CreateInterface();
property1.Type.Name = "Type 1";
lifeline.Represents = property1;
Come ulteriore alternativa, è possibile impostare il nome e il tipo di una linea di vita senza collegarla a un elemento collegabile:
ILifeline lifeline = interaction.CreateLifeline();
lifeline.Name = "c1";
lifeline.SetInstanceType("Customer");
System.Diagnostics.Debug.Assert(
lifeline.GetDisplayName() == "c1:Customer" );
Per creare messaggi
Per creare un messaggio, è necessario identificare i punti di inserimento nelle linee di vita di origine e di destinazione.Ad esempio:
interaction.CreateMessage( sourceInsertionPoint,
targetInsertionPoint,
MessageKind.Complete,
MessageSort.ASynchCall)
Per creare un messaggio con un'origine o una destinazione non definita:
interaction.CreateLostFoundMessage(MessageKind.Found, insertionPoint);
Sono disponibili diversi messaggi che è possibile utilizzare per identificare i punti di inserimento in tutti i punti chiave di una linea di vita:
Metodo su ILifeline |
Punto di inserimento |
---|---|
FindInsertionPointAtTop() |
Parte superiore della linea di vita. |
FindInsertionPointAtBottom() |
Parte inferiore della linea di vita. |
FindInsertionPointAfterMessage (IMessage previous) |
Un punto immediatamente dopo il messaggio specificato. |
FindInsertionPointAfterExecutionSpecification (IExecutionSpecification previous) |
Il punto può trovarsi sulla linea di vita o su un blocco specifiche esecuzione padre. |
FindInsertionPointAfterInteractionUse (IInteractionUse previous) |
Un punto che segue un utilizzo interazione. |
FindInsertionPointAfterCombinedFragment (ICombinedFragment previous) |
Un punto che segue un frammento combinato. |
FindInsertionPoint(IExecutionSpecification block) |
Parte superiore di un blocco esecuzione. |
FindInsertionPoint(IInteractionOperand fragment) |
Parte superiore di un operando di un frammento combinato. |
Quando si creano messaggi, evitare di definire un messaggio che interferirebbe con un altro messaggio.
Per creare frammenti combinati e utilizzi interazione
È possibile creare frammenti combinati e utilizzi interazione specificando un punto di inserimento su ogni linea di vita che deve essere analizzata dall'elemento.Evitare di specificare un set di punti che attraverserebbero un frammento o un messaggio esistente.
Interaction.CreateCombinedFragment(InteractionOperatorKind.Loop,
Interaction.Lifelines.Select(lifeline => lifeline.FindInsertionPointAtTop()));
Interaction.CreateInteractionUse(
Interaction.Lifelines.Select(lifeline => lifeline.FindInsertionPointAtTop()));
È inoltre possibile creare un frammento combinato che analizza un set esistente di messaggi.I messaggi devono tutti avere origine dalla stessa linea di vita o dallo stesso blocco di esecuzione.
ICombinedFragment cf = Interaction.CreateCombinedFragment(
InteractionOperatorKind.Loop,
Interaction.Lifelines.First().GetAllOutgoingMessages());
Un frammento combinato viene sempre creato con un solo operando.Per creare un nuovo operando, è necessario specificare l'operando esistente che si desidera inserire prima o dopo e se si desidera inserirlo dopo o prima:
// 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);
Risoluzione dei problemi
Le forme verranno visualizzate nelle posizioni errate se le modifiche non vengono completate con un'operazione UpdateShapePositions() o Layout().
La maggior parte di altri problemi è causata da punti di inserimento non allineati, in modo che nuovi messaggi o frammenti debbano incrociarsi con altri.I sintomi possono essere la mancata esecuzione di modifiche o la generazione di un'eccezione.L'eccezione potrebbe non essere generata finché non viene eseguita l'operazione UpdateShapePositions() o Layout().
Vedere anche
Riferimenti
Microsoft.VisualStudio.Uml.Interactions
Concetti
Estensione di modelli e diagrammi UML
Procedura: definire un comando di menu in un diagramma di modellazione
Procedura: definire un elemento personalizzato della Casella degli strumenti di modellazione