방법: 다이어그램에 모델 표시

업데이트: 2011년 3월

Visual Studio Ultimate 확장의 프로그램 코드에서 모델 요소가 다이어그램에 표시되는 방식을 제어할 수 있습니다.

  • 항목 내용

    • 다이어그램에 요소를 표시하려면

    • 요소를 나타내는 모양에 액세스

    • 모양 이동 및 크기 조정

    • 다이어그램에서 모양을 제거하려면

    • 다이어그램 열기 및 만들기

    • 예제: 모양 맞춤 명령

다이어그램에 요소를 표시하려면

사용 사례 또는 동작과 같은 요소를 만들면 사용자가 UML 모델 탐색기에서 이 요소를 볼 수 있지만 요소가 항상 자동으로 다이어그램에 나타나는 것은 아닙니다. 경우에 따라 요소를 표시하기 위해 코드를 작성해야 합니다. 다음 표에서는 이러한 추가 방법에 대해 간단히 설명합니다.

 

요소 형식

요소를 표시하는 코드

분류자

Class

Component

Actor

Use Case

지정된 다이어그램에서 관련된 모양을 만듭니다. 각 분류자에 대해 원하는 만큼 모양을 만들 수 있습니다.

diagram.Display<modelElementType>

(modelElement, parentShape,

xPosition , yPosition);

다이어그램의 최상위 모양에는 parentShape를 null로 설정합니다.

모양을 다른 모양 안에 표시하려면 다음과 같이 합니다.

IShape<IUseCase> usecaseShape =

useCaseDiagram.Display

(useCase,

subsystemShape,

subsystemShape.XPosition + 5,

subsystemShape.YPosition + 5);

참고참고
ILinkedUndo 트랜잭션 내에서 Display 메서드를 수행하면 IShape를 반환하지 않는 경우가 종종 있습니다.그러나 모양은 정확하게 만들어지고 IElement.Shapes()를 사용하여 액세스할 수 있습니다.

분류자의 자식

특성, 작업

파트, 포트

자동 - 코드가 필요하지 않습니다.

부모의 일부로 표시됩니다.

동작

상호 작용(시퀀스),

작업(Activity)

적절한 다이어그램에 동작을 바인딩합니다.

각 동작은 한 번에 최대 하나의 다이어그램에만 바인딩될 수 있습니다.

예를 들면 다음과 같습니다.

sequenceDiagram.Bind(interaction);

activityDiagram.Bind(activity);

동작의 자식

수명선, 메시지, 동작, 개체 노드

자동 - 코드가 필요하지 않습니다.

부모가 다이어그램에 바인딩되어 있는 경우 표시됩니다.

관계

연결, 일반화, 흐름, 종속성

자동 - 코드가 필요하지 않습니다.

양쪽 끝이 모두 표시되는 모든 다이어그램에 표시됩니다.

 

요소를 나타내는 모양에 액세스

요소를 나타내는 모양은 다음과 같이 형식에 속합니다.

IShape

IShape<ElementType>

여기서 ElementType은 IClass 또는 IUseCase와 같은 모델 요소의 형식입니다.

anElement.Shapes ()

열린 다이어그램에서 이 요소를 나타내는 모든 IShapes입니다.

anElement.Shapes(aDiagram)

특정 다이어그램에서 이 요소를 나타내는 모든 IShapes입니다.

anIShape.GetElement()

모양이 나타내는 IElement입니다. 일반적으로 이 형식은 IElement의 서브클래스로 캐스팅합니다.

anIShape.Diagram

모양을 포함하는 IDiagram입니다.

anIShape.ParentShape

anIShape를 포함하는 모양입니다. 예를 들어 포트 모양은 구성 요소 모양 내에 포함됩니다.

anIShape.ChildShapes

IShape 또는 IDiagram 내에 포함되는 모양입니다.

anIShape.GetChildShapes<IUseCase>()

IShape 또는 IDiagram 내에 포함되어 IUseCase와 같이 지정된 형식의 요소를 나타내는 모양입니다.

IShape iShape = ...;

IShape<IClass> classShape = iShape.ToIShape<IClass>();

IClass aClass = classShape.Element;

제네릭 IShape를 강력한 형식의 IShape<IElement>로 캐스팅합니다.

IShape<IClassifier> classifierShape;

IShape<IUseCase> usecaseShape =

classifierShape.ToIShape<IUseCase>();

매개 변수가 있는 한 모양 형식에서 다른 형식으로 모양을 캐스팅합니다.

모양 이동 및 크기 조정

anIShape.Move(x, y, [width], [height])

모양을 이동하거나 크기를 조정합니다.

IDiagram.EnsureVisible( IEnumerable<IShape> shapes, bool zoomToFit = false)

창을 활성화하고 지정된 모든 모양이 표시되도록 다이어그램을 스크롤합니다. 모양이 모두 다이어그램에 나타나야 합니다. zoomToFit이 true이면 모든 모양을 표시하는 데 필요할 경우 다이어그램이 확장됩니다.

이에 대한 예제를 보려면 맞춤 명령 정의를 참조하십시오.

다이어그램에서 모양을 제거하려면

일부 형식의 요소는 해당 요소를 삭제하지 않고 요소의 모양을 삭제할 수 있습니다.

모델 요소

형식을 제거하려면

분류자: 클래스, 인터페이스, 열거형, 행위자, 사용 사례 또는 구성 요소

shape.Delete();

동작: 상호 작용 또는 동작

프로젝트에서 다이어그램을 삭제할 수 있습니다. 경로를 가져오려면 IDiagram.FileName을 사용합니다.

모델에서 동작이 삭제되지는 않습니다.

다른 모든 모양

다른 모양은 다이어그램에서 명시적으로 삭제할 수 없습니다. 요소가 모델에서 삭제되거나 부모 모양이 다이어그램에서 제거되면 자동으로 모양이 없어집니다.

다이어그램 열기 및 만들기

명령 또는 제스처 확장에서 사용자의 현재 다이어그램에 액세스하려면

다음과 같이 가져온 이 속성을 클래스에 선언합니다.

[Import]

IDiagramContext Context { get; set; }

 

다음과 같이 메서드에서 다이어그램에 액세스합니다.

IClassDiagram classDiagram =

Context.CurrentDiagram as IClassDiagram;

참고

IDiagram과 해당 하위 형식(예: IClassDiagram)의 인스턴스는 처리 중인 명령 내에서만 유효합니다. 따라서 사용자에게 제어가 반환된 동안 유지되는 변수에 IDiagram 개체를 포함하는 것은 좋지 않습니다.

자세한 내용은 방법: 모델링 다이어그램의 메뉴 명령 정의를 참조하십시오.

열려 있는 다이어그램의 목록을 가져오려면

프로젝트에 현재 열려 있는 다이어그램의 목록을 가져오려면 다음을 사용합니다.

Context.CurrentDiagram.ModelStore.Diagrams()

프로젝트의 다이어그램에 액세스하려면

Visual Studio API를 사용하여 모델링 프로젝트 및 다이어그램을 열거나 만들 수 있습니다.

다음과 같이 EnvDTE.ProjectItem이 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)
  { ... } } }

IDiagram과 해당 하위 형식의 인스턴스는 Visual Studio로 제어를 반환한 후에는 유효하지 않습니다.

다음과 같이 Visual Studio 프로젝트에서 모델 저장소를 가져올 수도 있습니다.

Project project = ...;
IModelStore modelStore = (project as IModelingProject).Store;

예제: 모양 맞춤 명령

다음 코드는 모양을 반듯하게 맞추는 메뉴 명령을 구현합니다. 먼저 두 개 이상의 모양을 세로 또는 가로로 대략 맞춰서 배치해야 합니다. 그런 다음 맞춤 명령을 사용하여 가운데를 맞출 수 있습니다.

이 명령을 제공하려면 이 코드를 메뉴 명령 프로젝트에 추가한 다음 사용자들에게 결과 확장을 배포합니다. 자세한 내용은 방법: 모델링 다이어그램의 메뉴 명령 정의을 참조하십시오.

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

참고 항목

개념

UML 모델 및 다이어그램 확장

방법: UML 모델 탐색

기타 리소스

Sample: Align Shapes on a Diagram menu command

Sample: Creating Elements, Shapes and Stereotypes

변경 기록

날짜

변경 내용

이유

2011년 3월

맞춤 예제를 추가했습니다.

고객 의견