Cómo: Mostrar un modelo en diagramas
En el código del programa de una extensión de Visual Studio Ultimate, puede controlar el modo en que los elementos del modelo se muestran en los diagramas.
En este tema:
Para mostrar un elemento en un diagrama
Obtener acceso a las formas que representan un elemento
Mover y cambiar el tamaño de las formas
Para quitar una forma de un diagrama
Abrir y crear diagramas
Ejemplo: Comando para alinear formas
Para mostrar un elemento en un diagrama
Cuando crea un elemento, como un caso de uso o una acción, el usuario puede verlo en el Explorador de modelos UML, pero no siempre aparece automáticamente en un diagrama.En algunos casos, debe escribirse el código para que aparezca.En la siguiente tabla se resumen las alternativas.
Tipo de elemento |
Por ejemplo |
Para que aparezca, el código debe |
---|---|---|
Clasificador |
Class Component Actor Use Case |
Crear formas asociadas en los diagramas especificados.Puede crear cualquier número de formas para cada clasificador. diagram.Display<modelElementType> (modelElement, parentShape, xPosition , yPosition); Establezca parentShape en null para una forma en el nivel superior del diagrama. Para mostrar una forma dentro de otra: IShape<IUseCase> usecaseShape = useCaseDiagram.Display (useCase, subsystemShape, subsystemShape.XPosition + 5, subsystemShape.YPosition + 5);
Nota
Si ejecuta una operación Display dentro de una transacción ILinkedUndo, en ocasiones el método no devuelve ningún objeto IShape.Sin embargo, la forma se ha creado correctamente y puede obtenerse acceso a ella a través de IElement.Shapes()..
|
Elemento secundario del clasificador |
Atributo, operación, Elemento, puerto |
Automático: no se necesita código. Se muestra como un elemento del elemento primario. |
Comportamiento |
Interacción (secuencia) Actividad |
Enlazar el comportamiento con un diagrama adecuado. Cada comportamiento se puede enlazar como máximo a un único diagrama cada vez. Por ejemplo: sequenceDiagram.Bind(interaction); activityDiagram.Bind(activity); |
Elemento secundario del comportamiento |
Líneas de vida, mensajes, acciones, nodos de objeto |
Automático: no se necesita código. Se muestra si el elemento primario está enlazado a un diagrama. |
Relación |
Asociación, generalización, flujo, dependencia |
Automático: no se necesita código. Se muestra en todos los diagramas en los que aparecen los dos extremos. |
Obtener acceso a las formas que representan un elemento
La forma que representa un elemento pertenece a los tipos:
IShape
IShape<TipoDeElemento>
donde TipoDeElemento es un tipo del elemento del modelo, como IClass o IUseCase.
anElement.Shapes () |
Todas las IShapes que representan este elemento en los diagramas abiertos. |
anElement.Shapes(aDiagram) |
Todos los objetos IShapes que representan este elemento en un determinado diagrama. |
anIShape.GetElement() |
IElement que la forma representa.Normalmente lo convertiría en una subclase de IElement. |
anIShape.Diagram |
El IDiagram que contiene la forma. |
anIShape.ParentShape |
Forma que contiene anIShape.Por ejemplo, una forma de puerto está incluida en una forma de componente. |
anIShape.ChildShapes |
Formas incluidas en IShape o IDiagram. |
anIShape.GetChildShapes<IUseCase>() |
Formas incluidas en IShape o IDiagram que representan elementos del tipo especificado, como IUseCase. |
IShape iShape = ...; IShape<IClass> classShape = iShape.ToIShape<IClass>(); IClass aClass = classShape.Element; |
Convertir una IShape genérica a una IShape<IElement> fuertemente tipada. |
IShape<IClassifier> classifierShape; IShape<IUseCase> usecaseShape = classifierShape.ToIShape<IUseCase>(); |
Convertir una forma de un tipo parametrizado a otro. |
Mover y cambiar el tamaño de las formas
anIShape.Move(x, y, [width], [height]) |
Mover una forma o cambiar su tamaño. |
IDiagram.EnsureVisible( IEnumerable<IShape> shapes, bool zoomToFit = false) |
Active la ventana y desplace el diagrama para que todas las formas especificadas estén visibles.Las formas deben estar todas en el diagrama.Si zoomToFit es true, se escalará el diagrama si es necesario para que todas las formas estén visibles. |
Para obtener un ejemplo, vea Definir un comando de alineación.
Para quitar una forma de un diagrama
Puede eliminar formas de algunos tipos de elementos sin eliminar el elemento.
Elemento del modelo |
Para quitar la forma |
---|---|
Un clasificador: una clase, interfaz, enumeración, actor, caso de uso o componente |
shape.Delete(); |
Un comportamiento: interacción o actividad |
Puede eliminar el diagrama del proyecto.Use IDiagram.FileName para obtener la ruta de acceso. Con ello, no elimina el comportamiento del modelo. |
Cualquier otra forma |
No puede eliminar explícitamente otras formas de un diagrama.La forma desaparecerá automáticamente si el elemento se elimina del modelo o si la forma primaria se quita del diagrama. |
Abrir y crear diagramas
Para tener acceso al diagrama actual del usuario a partir de una extensión de comandos o gestos
Declare esta propiedad importada en su clase:
[Import]
IDiagramContext Context { get; set; }
A través de un método, obtenga acceso al diagrama:
IClassDiagram classDiagram =
Context.CurrentDiagram as IClassDiagram;
[!NOTA]
Una instancia de IDiagram (y sus subtipos como IClassDiagram) solo es válida dentro del comando que se está procesando.No es recomendable mantener un objeto IDiagram en una variable que se conserva mientras el control se devuelve al usuario.
Para obtener más información, vea Cómo: Definir un comando de menú en un diagrama de modelado.
Para obtener una lista de los diagramas abiertos
Una lista de los diagramas que están abiertos actualmente en el proyecto:
Context.CurrentDiagram.ModelStore.Diagrams()
Para tener acceso a los diagramas de un proyecto
Se puede utilizar la API de Visual Studio para abrir y crear proyectos y diagramas de modelado.
Observe la conversión de EnvDTE.ProjectItem a IDiagramContext.
using EnvDTE; // Visual Studio API
...
[Import]
public IServiceProvider ServiceProvider { get; set; }
...
// Get Visual Studio API
DTE dte = ServiceProvider.GetService(typeof(DTE)) as DTE;
// Get current Visual Studio project
Project project = dte.ActiveDocument.ProjectItem.ContainingProject;
// Open and process every diagram in the project.
foreach (ProjectItem item in project.ProjectItems)
{
// Cast ProjectItem to IDiagramContext
IDiagramContext context = item as IDiagramContext;
if (context == null)
{
// This is not a diagram file.
continue;
}
// Open the file and give the window the focus.
if (!item.IsOpen)
{
item.Open().Activate();
}
// Get the diagram.
IDiagram diagram = context.CurrentDiagram;
// Deal with specific diagram types.
ISequenceDiagram seqDiagram = diagram as ISequenceDiagram;
if (seqDiagram != null)
{ ... } } }
Las instancias de IDiagram y sus subtipos no son válidos cuando se devuelve el control a Visual Studio.
También puede obtener el almacén de modelos de un proyecto de Visual Studio:
Project project = ...;
IModelStore modelStore = (project as IModelingProject).Store;
Ejemplo: Comando para alinear formas
El siguiente código implementa un comando de menú que alinea las formas de manera correcta.El usuario primero debe colocar dos o más formas con una alineación aproximada, ya sea vertical u horizontalmente.A continuación, puede usarse el comando de alineación para alinear las formas tomando como referencia su punto central.
Para que el comando esté disponible, agregue este código a un proyecto de comando de menú y, a continuación, implemente la extensión resultante para sus usuarios.Para obtener más información, vea Cómo: Definir un comando de menú en un diagrama de modelado.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
namespace AlignCommand
{
// Implements a command to align shapes in a UML class diagram.
// The user first selects shapes that are roughly aligned either vertically or horizontally.
// This command will straighten them up.
// Place this file in a menu command extension project.
// See https://msdn.microsoft.com/library/ee329481.aspx
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension] // TODO: Add other diagram types if needed
class CommandExtension : ICommandExtension
{
/// <summary>
/// See https://msdn.microsoft.com/library/ee329481.aspx
/// </summary>
[Import]
IDiagramContext context { get; set; }
/// <summary>
/// Transaction context.
/// See https://msdn.microsoft.com/library/ee330926.aspx
/// </summary>
[Import]
ILinkedUndoContext linkedUndo { get; set; }
/// <summary>
/// Called when the user selects the command.
/// </summary>
/// <param name="command"></param>
public void Execute(IMenuCommand command)
{
Align(context.CurrentDiagram.SelectedShapes);
}
/// <summary>
/// Called when the user right-clicks on the diagram.
/// Determines whether the command is enabled.
/// </summary>
/// <param name="command"></param>
public void QueryStatus(IMenuCommand command)
{
IEnumerable<IShape> currentSelection = context.CurrentDiagram.SelectedShapes;
// Make it visible if there are shapes selected:
command.Visible = currentSelection.Count() > 0 && !(currentSelection.FirstOrDefault() is IDiagram);
// Make it enabled if there are two or more shapes that are roughly in line:
command.Enabled = currentSelection.Count() > 1
&& (HorizontalAlignCenter(currentSelection) > 0.0
|| VerticalAlignCenter(currentSelection) > 0.0);
}
/// <summary>
/// Title of the menu command.
/// </summary>
public string Text
{
get { return "Align Shapes"; }
}
/// <summary>
/// Find a horizontal line that goes through a list of shapes.
/// </summary>
/// <param name="shapes"></param>
/// <returns></returns>
private static double HorizontalAlignCenter(IEnumerable<IShape> shapes)
{
double Y = -1.0;
double top = 0.0, bottom = shapes.First().Bottom();
foreach (IShape shape in shapes)
{
top = Math.Max(top, shape.Top());
bottom = Math.Min(bottom, shape.Bottom());
}
if (bottom > top) Y = (bottom + top) / 2.0;
return Y;
}
/// <summary>
/// Find a vertical line that goes through a list of shapes.
/// </summary>
/// <param name="shapes"></param>
/// <returns></returns>
private static double VerticalAlignCenter(IEnumerable<IShape> shapes)
{
double X = -1.0;
double left = 0.0, right = shapes.First().Right();
foreach (IShape shape in shapes)
{
left = Math.Max(left, shape.Left());
right = Math.Min(right, shape.Right());
}
if (right > left) X = (right + left) / 2.0;
return X;
}
/// <summary>
/// Line up those shapes that are roughly aligned.
/// </summary>
/// <param name="shapes"></param>
private void Align(IEnumerable<IShape> shapes)
{
if (shapes.Count() > 1)
{
// The shapes must all overlap either horizontally or vertically.
// Find a horizontal line that is covered by all the shapes:
double Y = HorizontalAlignCenter(shapes);
if (Y > 0.0) // Negative if they don't overlap.
{
// Adjust all the shape positions in one transaction:
using (ILinkedUndoTransaction t = linkedUndo.BeginTransaction("align"))
{
foreach (IShape shape in shapes)
{
shape.AlignYCenter(Y);
}
t.Commit();
}
}
else
{
// Find a vertical line that is covered by all the shapes:
double X = VerticalAlignCenter(shapes);
if (X > 0.0) // Negative if they don't overlap.
{
// Adjust all the shape positions in one transaction:
using (ILinkedUndoTransaction t = linkedUndo.BeginTransaction("align"))
{
foreach (IShape shape in shapes)
{
shape.AlignXCenter(X);
}
t.Commit();
}
}
}
}
}
}
/// <summary>
/// Convenience extensions for IShape.
/// </summary>
public static class IShapeExtension
{
public static double Bottom(this IShape shape)
{
return shape.YPosition + shape.Height;
}
public static double Top(this IShape shape)
{
return shape.YPosition;
}
public static double Left(this IShape shape)
{
return shape.XPosition;
}
public static double Right(this IShape shape)
{
return shape.XPosition + shape.Width;
}
public static void AlignYCenter(this IShape shape, double Y)
{
shape.Move(shape.XPosition, Y - shape.YCenter());
}
public static void AlignXCenter(this IShape shape, double X)
{
shape.Move(X - shape.XCenter(), shape.YPosition);
}
/// <summary>
/// We can adjust what bit of the shape we want to be aligned.
/// The default is the center of the shape.
/// </summary>
/// <param name="shape"></param>
/// <returns></returns>
public static double YCenter(this IShape shape)
{
return shape.Height / 2.0;
}
/// <summary>
/// We can adjust what bit of the shape we want to be aligned.
/// The default is the center of the shape.
/// </summary>
/// <param name="shape"></param>
/// <returns></returns>
public static double XCenter(this IShape shape)
{
return shape.Width / 2.0;
}
}
}
Vea también
Conceptos
Ampliar modelos y diagramas UML
Cómo: Navegar por el modelo UML