방법: 모델링 다이어그램의 제스처 처리기 정의

Visual Studio Ultimate에서는 사용자가 항목을 두 번 클릭하거나 UML 다이어그램으로 끌 때 수행되는 명령을 정의할 수 있습니다. 이러한 확장을 Visual Studio Integration Extension (VSIX) 에 패키지 할 수 있고, 이것을 다른 Visual Studio Ultimate 사용자에게 배포할 수 있습니다.

끌어 오려는 요소 형식과 다이어그램 형식에 대한 기본 동작이 이미 있는 경우에는 이 동작에 추가하거나 이 동작을 재정의하지 못할 수 있습니다.

요구 사항

제스처 처리기 만들기

UML 디자이너를 위한 제스처 처리기를 정의하려면 제스처 처리기의 동작을 정의하는 클래스를 만들어서 VSIX(Visual Studio Integration Extension)에 포함합니다. VSIX는 처리기를 설치할 수 있는 컨테이너 역할을 합니다. 다음과 같은 두 가지 방법으로 제스처 처리기를 정의할 수도 있습니다.

  • 프로젝트 템플릿을 사용하여 자체 VSIX에 제스처 처리기 만들기. 이는 보다 빠른 방법입니다. 처리기를 유효성 검사 확장, 사용자 지정 도구 상자 항목, 메뉴 명령 등의 다른 유형의 확장과 결합하지 않으려는 경우 이 방법을 사용합니다.

  • 별도의 제스처 처리기와 VSIX 프로젝트 만들기. 같은 VSIX에 여러 유형의 확장을 결합하려는 경우 이 방법을 사용합니다. 예를 들어 제스처 처리기에서 모델이 특정 제약 조건을 준수할 것으로 예상하는 경우 이를 동일한 VSIX에 유효성 검사 메서드로 포함할 수 있습니다.

자체 VSIX에 제스처 처리기를 만들려면

  1. 새 프로젝트 대화 상자의 모델링 프로젝트에서 제스처 확장을 선택합니다.

  2. 새 프로젝트에서 .cs 파일을 열고 GestureExtension 클래스를 수정하여 제스처 처리기를 구현합니다.

    자세한 내용은 제스처 처리기 구현을 참조하십시오.

  3. F5 키를 눌러 제스처 처리기를 테스트합니다. 자세한 내용은 제스처 처리기 실행을 참조하십시오.

  4. 프로젝트에서 빌드된 bin\*\*.vsix 파일을 복사하여 제스처 처리기를 다른 컴퓨터에 설치합니다. 자세한 내용은 제스처 처리기 설치를 참조하십시오.

대안 절차는 다음과 같습니다.

제스처 처리기에 대한 별도 클래스 라이브러리(DLL) 프로젝트를 만들려면

  1. 새 Visual Studio 솔루션 또는 기존 솔루션에 클래스 라이브러리 프로젝트를 만듭니다.

    1. 파일 메뉴에서 새로 만들기, 프로젝트를 선택합니다.

    2. 설치된 템플릿에서 Visual C# 또는 Visual Basic을 확장한 다음, 가운데 열에서 클래스 라이브러리를 선택합니다.

  2. 프로젝트에 다음 참조를 추가합니다.

    Microsoft.VisualStudio.Modeling.Sdk.12.0

    Microsoft.VisualStudio.Modeling.Sdk.Diagrams.12.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

    System.Windows.Forms

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer – 레이어 다이어그램을 확장하는 경우에만 필요합니다. 자세한 내용은 레이어 다이어그램 확장을 참조하십시오.

  3. 프로젝트에 클래스 파일을 추가하고 이 파일의 내용을 다음 코드로 설정합니다.

    참고

    네임스페이스 및 클래스 이름을 원하는 대로 변경합니다.

    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.Modeling.Diagrams;
    using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
    using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
    using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
    using Microsoft.VisualStudio.Modeling;
    using Microsoft.VisualStudio.Uml.Classes;
    // ADD other UML namespaces if required
    
    namespace MyGestureHandler // CHANGE
    {
      // DELETE any of these attributes if the handler
      // should not work with some types of diagram.
      [ClassDesignerExtension]
      [ActivityDesignerExtension]
      [ComponentDesignerExtension]
      [SequenceDesignerExtension]
      [UseCaseDesignerExtension]
      // [LayerDesignerExtension]
    
      // Gesture handlers must export IGestureExtension:
      [Export(typeof(IGestureExtension))]
      // CHANGE class name
      public class MyGesture1 : IGestureExtension
      {
        [Import]
        public IDiagramContext DiagramContext { get; set; }
    
        /// <summary>
        /// Called when the user double-clicks on the diagram
        /// </summary>
        /// <param name="targetElement"></param>
        /// <param name="diagramPointEventArgs"></param>
        public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target shape, if any. Null if the target is the diagram.
          IShape targetIShape = targetElement.CreateIShape();
    
          // Do something...
        }
    
        /// <summary>
        /// Called repeatedly when the user drags from anywhere on the screen.
        /// Return value should indicate whether a drop here is allowed.
        /// </summary>
        /// <param name="targetMergeElement">References the element to be dropped on.</param>
        /// <param name="diagramDragEventArgs">References the element to be dropped.</param>
        /// <returns></returns>
        public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
    
          // Get the target element, if any. Null if the target is the diagram.
          IShape targetIShape = targetMergeElement.CreateIShape();
    
          // This example allows drag of any UML elements.
          return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0;
        }
    
    
        /// <summary>
        /// Execute the action to be performed on the drop.
        /// </summary>
        /// <param name="targetDropElement"></param>
        /// <param name="diagramDragEventArgs"></param>
        public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs)
        {
          // CHANGE THIS CODE FOR YOUR APPLICATION.
        }
    
        /// <summary>
        /// Retrieves UML IElements from drag arguments.
        /// Works for drags from UML diagrams.
        /// </summary>
        private IEnumerable<IElement> GetModelElementsFromDragEvent
                (DiagramDragEventArgs dragEvent)
        {
          //ElementGroupPrototype is the container for
          //dragged and copied elements and toolbox items.
          ElementGroupPrototype prototype =
             dragEvent.Data.
             GetData(typeof(ElementGroupPrototype))
                  as ElementGroupPrototype;
          // Locate the originals in the implementation store.
          IElementDirectory implementationDirectory =
             dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
    
          return prototype.ProtoElements.Select(
            prototypeElement =>
            {
              ModelElement element = implementationDirectory
                .FindElement(prototypeElement.ElementId);
              ShapeElement shapeElement = element as ShapeElement;
              if (shapeElement != null)
              {
                // Dragged from a diagram.
                return shapeElement.ModelElement as IElement;
              }
              else
              {
                // Dragged from UML Model Explorer.
                return element as IElement;
              }
            });
        }
    
      }
    }
    

    메서드에 무엇을 넣을지에 대한 자세한 내용은 제스처 처리기 구현을 참조하십시오.

명령 설치를 위한 컨테이너 역할을 하는 VSIX 프로젝트에 메뉴 명령을 추가해야 합니다. 원하는 경우 같은 VSIX에 다른 구성 요소를 포함할 수 있습니다.

VSIX 프로젝트에 별도의 제스처 처리기를 추가하려면

  1. 자체 VSIX가 있는 제스처 처리를 만든 경우 이 절차가 필요 없습니다.

  2. 솔루션에 VSIX 프로젝트가 이미 있는 경우가 아니면 새로 만듭니다.

    1. 솔루션 탐색기에서, 솔루션의 바로 가기 메뉴에서, 추가, 새 프로젝트를 선택하세요.

    2. 설치된 템플릿에서, Visual C# 또는 Visual Basic을 확장한 다음, 확장성을 선택합니다. 가운데 열에서, VSIX 프로젝트를 선택합니다.

  3. VSIX 프로젝트를 솔루션의 시작 프로젝트로 설정합니다.

    • 솔루션 탐색기에서, VSIX 프로젝트의 바로 가기 메뉴에서 스타트업 프로젝트로 설정을 선택합니다.
  4. source.extension.vsixmanifest의 콘텐츠에서 제스처 처리기 클래스 라이브러리 프로젝트를 MEF 구성 요소로 추가합니다:

    1. 메타 데이터 탭에서 VSIX의 이름을 설정 합니다.

    2. 설치 대상 탭에서 Visual Studio Ultimate와 Premium을 대상으로 설정 합니다.

    3. 자산 탭에서 새로 만들기를 선택하고 설정 대화 상자에서 다음을 설정합니다:

      유형 = MEF 구성 요소

      소스 = 현재 솔루션에 있는 프로젝트

      프로젝트 = Your class library project

제스처 처리기 실행

테스트 목적으로 디버그 모드에서 제스처 처리기를 실행합니다.

제스처 처리기를 테스트하려면

  1. F5 키를 누르거나, 디버그 메뉴에서 디버깅 시작을 클릭합니다.

    실험적 Visual Studio 인스턴스가 시작됩니다.

    문제 해결: 새 Visual Studio가 시작되지 않는 경우:

    • 하나 이상의 프로젝트가 있는 경우 VSIX 프로젝트가 솔루션의 시작 프로젝트로 설정되어 있는지 확인하십시오.

    • 솔루션 탐색기의 스타트업 또는 프로젝트의 바로 가기 메뉴에서 속성을 선택합니다. 프로젝트 속성 편집기에서 디버그 탭을 선택합니다. 시작 외부 프로그램 필드의 문자열이 대개 다음과 같은 Visual Studio의 전체 경로 이름인지 확인합니다.

      C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe

  2. 실험적 Visual Studio에서 모델링 프로젝트 및 모델링 다이어그램을 열거나 만듭니다. 제스처 처리기 클래스의 특성에 나열된 형식 중 하나에 속하는 다이어그램을 사용하십시오.

  3. 다이어그램에서 아무 곳이나 두 번 클릭합니다. 두 번 클릭 처리기가 호출되어야 합니다.

  4. 요소를 UML 탐색기에서 다이어그램으로 끌어 옵니다. 끌기 처리기가 호출되어야 합니다.

문제 해결: 제스처 처리기가 작동하지 않으면 다음을 확인하십시오.

  • 제스처 처리기 프로젝트가 VSIX 프로젝트의 source.extensions.manifest에서 자산 탭에 MEF 구성 요소로 나열되어 있는지 확인합니다.

  • Import 및 Export 특성의 모든 매개 변수가 올바른지 확인합니다.

  • CanDragDrop 메서드가 false를 반환하지 않는지 확인합니다.

  • UML 클래스와 시퀀스 다이어그램 등 사용하는 모델 다이어그램의 형식이 [ClassDesignerExtension], [SequenceDesignerExtension] 등의 제스처 처리기 클래스 특성 중 하나로 나열되어 있는지 확인합니다.

  • 이 형식의 대상 및 끌어 놓은 요소에 대해 이미 정의된 기본 제공 기능이 있지 않은지 확인합니다.

제스처 처리기 구현

제스처 처리기 메서드

제스처 처리기 클래스는 IGestureExtension을 구현하고 내보냅니다. 정의해야 할 메서드는 다음과 같습니다.

bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

dragEvent에서 참조되는 소스 요소를 이 대상에 놓을 수 있도록 하려면 true를 반환합니다.

이 메서드는 모델을 변경하면 안 됩니다. 사용자가 마우스를 움직일 때 화살표 상태를 결정하는 데 사용되므로 빠르게 작동해야 합니다.

void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent)

dragEvent에서 참조되는 소스 개체 및 대상을 기반으로 모델을 업데이트합니다.

사용자가 끌기를 완료하고 마우스 단추를 놓으면 호출됩니다.

void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent)

target은 사용자가 두 번 클릭한 모양입니다.

UML뿐만 아니라 파일, .NET 클래스 뷰의 노드, 아키텍처 탐색기 노드 등 다양한 다른 항목도 허용할 수 있는 처리기를 작성할 수 있습니다. serialize된 형식의 항목을 디코딩할 수 있는 OnDragDrop 메서드를 작성하는 경우 사용자는 이러한 항목 중 어떤 것이라도 UML 다이어그램으로 끌어 올 수 있습니다. 디코딩 메서드는 항목 형식에 따라 다릅니다.

이러한 메서드의 매개 변수는 다음과 같습니다.

  • ShapeElement target. 사용자가 항목을 끌어 온 대상 모양 또는 다이어그램입니다.

    ShapeElement는 UML 모델링 도구의 기반이 되는 구현의 클래스입니다. UML 모델과 다이어그램이 일관되지 않은 상태가 되는 위험을 줄이려면 이 클래스의 메서드를 직접적으로 사용하지 않는 것이 좋습니다. 대신 요소를 IShape에 래핑한 다음 방법: 다이어그램에 모델 표시에 설명된 방법을 사용합니다.

    • IShape를 가져오려면 다음을 사용합니다.

      IShape targetIShape = target.CreateIShape(target);
      
    • 끌기 또는 두 번 클릭 작업의 대상 모델 요소를 가져오려면 다음을 사용합니다.

      IElement target = targetIShape.Element;
      

      좀 더 구체적인 형식의 요소로 캐스팅할 수 있습니다.

    • UML 모델을 포함하는 UML 모델 저장소를 가져오려면 다음을 사용합니다.

      IModelStore modelStore = 
        targetIShape.Element.GetModelStore(); 
      
    • 호스트 및 서비스 공급자에 액세스하려면

      target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
      
  • DiagramDragEventArgs eventArgs. 이 매개 변수는 끌기 작업의 소스 개체에 대한 serialize된 형식을 전달합니다.

    System.Windows.Forms.IDataObject data = eventArgs.Data;  
    

    Visual Studio의 서로 다른 부분이나 Windows 데스크톱에서 다양한 종류의 요소를 다이어그램으로 끌어 올 수 있습니다. 각 요소는 형식에 따라 각기 다른 방식으로 IDataObject에 인코딩됩니다. 여기에서 요소를 추출하려면 해당 개체 형식에 대한 설명서를 참조하십시오.

    소스 개체가 UML 모델 탐색기나 다른 UML 다이어그램에서 끌어 온 UML 요소인 경우에는 방법: IDataObject에서 UML 모델 요소 가져오기를 참조하십시오.

메서드 코드 작성

모델을 읽고 업데이트하는 코드를 작성하는 방법에 대한 자세한 내용은 UML API를 사용한 프로그래밍을 참조하십시오.

끌기 작업에서 모델 정보에 액세스하는 방법에 대한 자세한 내용은 방법: IDataObject에서 UML 모델 요소 가져오기를 참조하십시오.

시퀀스 다이어그램을 처리하는 경우에는 방법: UML API를 사용하여 시퀀스 다이어그램 편집을 참조하십시오.

메서드의 매개 변수 외에, 현재 다이어그램 및 모델에 액세스할 수 있게 해 주는 클래스에서 가져온 속성을 선언할 수도 있습니다.

[Import] public IDiagramContext DiagramContext { get; set; }

IDiagramContext를 선언하면 다이어그램, 현재 선택 항목 및 모델에 액세스하는 메서드의 코드를 작성할 수 있습니다.

IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}

자세한 내용은 방법: UML 모델 탐색을 참조하십시오.

확장 설치 및 제거

자신이 사용하는 컴퓨터와 다른 컴퓨터에 둘 다 Visual Studio 확장을 설치할 수 있습니다.

확장을 설치하려면

  1. 컴퓨터에서 VSIX 프로젝트에 의해 빌드된 .vsix 파일을 찾습니다.

    1. 솔루션 탐색기에서, VSIX 프로젝트 바로 가기 메뉴에서, Windows 탐색기에서 폴더 열기 를 선택합니다.

    2. bin\*\YourProject.vsix파일 위치를 찾습니다

  2. 확장을 설치할 대상 컴퓨터에 .vsix 파일을 복사합니다. 대상 컴퓨터는 현재 사용 중인 컴퓨터일 수도 있고 다른 컴퓨터일 수도 있습니다.

    대상 컴퓨터에는 source.extension.vsixmanifest에 지정한 Visual Studio 버전 중 하나가 있어야 합니다.

  3. 대상 컴퓨터에서 .vsix 파일을 엽니다.

    Visual Studio Extension 설치 관리자가 열리고 확장이 설치됩니다.

  4. Visual Studio를 시작하거나 다시 시작합니다.

확장을 제거하려면

  1. 도구 메뉴에서 확장 관리자를 선택합니다.

  2. 설치된 확장을 확장합니다.

  3. 확장을 선택하고 제거를 선택합니다.

드물기는 하지만 잘못된 확장은 로드되지 않으며 오류 창에 보고서가 만들어지지만 확장 관리자에는 나타나지 않습니다. 이 경우에는 다음 위치에서 파일을 삭제하여 확장을 제거할 수 있습니다.

%LocalAppData%\Local\Microsoft\VisualStudio\12.0\Extensions

예제

다음 샘플에서는 구성 요소 다이어그램에서 끌어 온 구성 요소의 파트 및 포트를 기반으로 시퀀스 다이어그램에서 수명선을 만드는 방법을 보여 줍니다.

이 샘플을 테스트하려면 F5 키를 누릅니다. 그러면 실험 모드의 Visual Studio 인스턴스가 열립니다. 이 인스턴스에서 UML 모델을 열고 구성 요소 다이어그램에 구성 요소를 만듭니다. 이 구성 요소에 일부 인터페이스 및 내부 구성 요소 파트를 추가합니다. 인터페이스 및 파트를 선택합니다. 그런 다음 인터페이스와 파트를 시퀀스 다이어그램으로 끌어 옵니다. 구성 요소 다이어그램에서 시퀀스 다이어그램의 탭으로 끌어 온 다음 시퀀스 다이어그램까지 끕니다. 각 인터페이스 및 파트에 대해 수명선이 나타납니다.

시퀀스 다이어그램에 상호 작용을 바인딩하는 방법에 대한 자세한 내용은 방법: UML API를 사용하여 시퀀스 다이어그램 편집을 참조하십시오.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;

/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
  [Import]
  public IDiagramContext Context { get; set; }

  /// <summary>
  /// Called by the modeling framework when
  /// the user drops something on a target.
  /// </summary>
  /// <param name="target">The target shape or diagram </param>
  /// <param name="dragEvent">The item being dragged</param>
  public void OnDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    ISequenceDiagram diagram = Context.CurrentDiagram
            as ISequenceDiagram;
    IInteraction interaction = diagram.Interaction;
    if (interaction == null)
    {
      // Sequence diagram is empty: create an interaction.
      interaction = diagram.ModelStore.Root.CreateInteraction();
      interaction.Name = Context.CurrentDiagram.Name;
      diagram.Bind(interaction);
    }
    foreach (IConnectableElement connectable in
       GetConnectablesFromDrag(dragEvent))
    {
      ILifeline lifeline = interaction.CreateLifeline();
      lifeline.Represents = connectable;
      lifeline.Name = connectable.Name;
    }
  }

  /// <summary>
  /// Called by the modeling framework to determine whether
  /// the user can drop something on a target.
  /// Must not change anything.
  /// </summary>
  /// <param name="target">The target shape or diagram</param>
  /// <param name="dragEvent">The item being dragged</param>
  /// <returns>true if this item can be dropped on this target</returns>
  public bool CanDragDrop(ShapeElement target,
           DiagramDragEventArgs dragEvent)
  {
    IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
    return connectables.Count() > 0;
  }

  ///<summary>
  /// Get dragged parts and ports of an IComponent.
  ///</summary>
  private IEnumerable<IConnectableElement>
    GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
  {
    foreach (IElement element in
      GetModelElementsFromDragEvent(dragEvent))
    {
      IConnectableElement part = element as IConnectableElement;
      if (part != null)
      {
        yield return part;
      }
    }
  }

  /// <summary>
  /// Retrieves UML IElements from drag arguments.
  /// Works for drags from UML diagrams.
  /// </summary>
  private IEnumerable<IElement> GetModelElementsFromDragEvent
          (DiagramDragEventArgs dragEvent)
  {
    //ElementGroupPrototype is the container for
    //dragged and copied elements and toolbox items.
    ElementGroupPrototype prototype =
       dragEvent.Data.
       GetData(typeof(ElementGroupPrototype))
            as ElementGroupPrototype;
    // Locate the originals in the implementation store.
    IElementDirectory implementationDirectory =
       dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;

    return prototype.ProtoElements.Select(
      prototypeElement =>
      {
        ModelElement element = implementationDirectory
          .FindElement(prototypeElement.ElementId);
        ShapeElement shapeElement = element as ShapeElement;
        if (shapeElement != null)
        {
          // Dragged from a diagram.
          return shapeElement.ModelElement as IElement;
        }
        else
        {
          // Dragged from UML Model Explorer.
          return element as IElement;
        }
      });
  }

  public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
  {
  }
}

GetModelElementsFromDragEvent()의 코드에 대한 설명은 방법: IDataObject에서 UML 모델 요소 가져오기에 나와 있습니다.

참고 항목

개념

방법: 모델링 확장 정의 및 설치

UML 모델 및 다이어그램 확장

방법: 모델링 다이어그램의 메뉴 명령 정의

방법: UML 모델에 대한 유효성 검사 제약 조건 정의

UML API를 사용한 프로그래밍