Compartir a través de


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);

NotaNota
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

Otros recursos

Ampliar modelos y diagramas UML

Cómo: Navegar por el modelo UML

Ejemplo Align Shapes on a Diagram menu command

Ejemplo Creating Elements, Shapes and Stereotypes

Historial de cambios

Fecha

Historial

Motivo

Marzo de 2011

Se ha agregado un ejemplo sobre alineación.

Comentarios de los clientes.