방법: 모델링 다이어그램의 메뉴 명령 정의
Visual Studio Ultimate에서는 사용자가 UML 다이어그램을 마우스 오른쪽 단추로 클릭할 때 나타나는 추가 메뉴 항목을 정의할 수 있습니다. 사용자가 다이어그램의 요소를 마우스 오른쪽 단추로 클릭할 때 메뉴 명령을 사용할 수 있도록 표시할지 여부를 제어할 수 있으며, 사용자가 메뉴 항목을 선택할 때 실행되는 코드를 작성할 수 있습니다. 이러한 확장을 VSIX(Visual Studio Integration Extension)에 패키지하여 다른 Visual Studio Ultimate 사용자에게 배포할 수 있습니다.
요구 사항
Visual Studio 2010 Visualization & Modeling SDK. 자세한 내용은 Code Gallery의 Visual Studio Visualization and Modeling SDK를 참조하십시오.
메뉴 명령 정의
UML 디자이너를 위한 메뉴 명령을 만들려면 명령의 동작을 정의하는 클래스를 만들어서 VSIX(Visual Studio Integration Extension)에 포함합니다. VSIX는 명령을 설치할 수 있는 컨테이너 역할을 합니다. 다음과 같은 두 가지 방법으로 메뉴 명령을 정의할 수도 있습니다.
프로젝트 템플릿을 사용하여 자체 VSIX에 메뉴 명령 만들기. 이는 보다 빠른 방법입니다. 메뉴 명령을 유효성 검사 확장, 사용자 지정 도구 상자 항목, 제스처 처리기 등의 다른 유형의 확장과 결합하지 않으려는 경우 이 방법을 사용합니다.
별도의 메뉴 명령과 VSIX 프로젝트 만들기. 같은 VSIX에 여러 유형의 확장을 결합하려는 경우 이 방법을 사용합니다. 예를 들어 메뉴 명령에서 모델이 특정 제약 조건을 준수할 것으로 예상하는 경우 이를 동일한 VSIX에 유효성 검사 메서드로 포함할 수 있습니다.
자체 VSIX에 메뉴 명령을 만들려면
새 프로젝트 대화 상자의 모델링 프로젝트에서 명령 확장을 선택합니다.
새 프로젝트에서 .cs 파일을 열고 CommandExtension 클래스를 수정하여 명령을 구현합니다.
자세한 내용은 메뉴 명령 구현을 참조하십시오.
새 클래스를 정의하여 이 프로젝트에 명령을 더 추가할 수 있습니다.
F5 키를 눌러 메뉴 명령을 테스트합니다. 자세한 내용은 메뉴 명령 실행을 참조하십시오.
프로젝트에서 빌드된 bin\*\*.vsix 파일을 복사하여 메뉴 명령을 다른 컴퓨터에 설치합니다. 자세한 내용은 메뉴 명령 설치를 참조하십시오.
클래스 라이브러리(DLL) 프로젝트에 별도의 메뉴 명령을 만들려면
새 Visual Studio 솔루션 또는 기존 솔루션에 클래스 라이브러리 프로젝트를 만듭니다.
파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 클릭합니다.
설치된 템플릿에서 Visual C# 또는 Visual Basic을 클릭하고 가운데 열에서 클래스 라이브러리를 클릭합니다.
새 솔루션을 만들지 아니면 이미 열어 놓은 VSIX 솔루션에 구성 요소를 추가할지를 나타내도록 솔루션을 설정합니다.
프로젝트 이름 및 위치를 설정하고 확인을 클릭합니다.
프로젝트에 다음 참조를 추가합니다.
참조
수행할 수 있는 작업
System.ComponentModel.Composition
MEF(Managed Extensibility Framework)를 사용하여 구성 요소를 정의할 수 있습니다.
Microsoft.VisualStudio.Uml.Interfaces
모델 요소의 속성을 읽고 변경할 수 있습니다.
Microsoft.VisualStudio.ArchitectureTools.Extensibility
모델 요소를 만들고 다이어그램에서 모양을 수정할 수 있습니다.
Microsoft.VisualStudio.Modeling.Sdk.10.0
모델 이벤트 처리기를 정의할 수 있습니다.
일련의 변경 내용을 모델에 캡슐화할 수 있습니다. 자세한 내용은 방법: 트랜잭션을 사용하여 모델 업데이트 연결을 참조하십시오.
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.10.0
(항상 필요하지는 않음)
제스처 처리기에 대한 추가 다이어그램 요소에 액세스할 수 있습니다.
Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer
레이어 다이어그램의 명령에만 필요함. 자세한 내용은 레이어 다이어그램의 확장 만들기를 참조하십시오.
레이어 다이어그램에 명령을 정의할 수 있습니다.
프로젝트에 클래스 파일을 추가하고 이 파일의 내용을 다음 코드로 설정합니다.
참고
네임스페이스, 클래스 이름 및 Text 반환 값을 원하는 대로 변경하십시오.
using System.ComponentModel.Composition; using System.Linq; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml; using Microsoft.VisualStudio.Modeling.ExtensionEnablement; using Microsoft.VisualStudio.Uml.AuxiliaryConstructs; using Microsoft.VisualStudio.Uml.Classes; // ADD other UML namespaces if required namespace UMLmenu1 // CHANGE { // DELETE any of these attributes if the command // should not appear in some types of diagram. [ClassDesignerExtension] [ActivityDesignerExtension] [ComponentDesignerExtension] [SequenceDesignerExtension] [UseCaseDesignerExtension] // [LayerDesignerExtension] // if you have installed Feature Pack 1 // All menu commands must export ICommandExtension: [Export (typeof(ICommandExtension))] // CHANGE class name public class Menu1 : ICommandExtension { [Import] public IDiagramContext DiagramContext { get; set; } public void QueryStatus(IMenuCommand command) { // Set command.Visible or command.Enabled to false // to disable the menu command. command.Visible = command.Enabled = true; } public string Text { get { return "MENU COMMAND LABEL"; } } public void Execute(IMenuCommand command) { // A selection of starting points: 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 (IElement element in modelStore.AllInstances<IClass>()) { } } } }
메서드에 무엇을 넣을지에 대한 자세한 내용은 메뉴 명령 구현을 참조하십시오.
명령 설치를 위한 컨테이너 역할을 하는 VSIX 프로젝트에 메뉴 명령을 추가해야 합니다. 원하는 경우 같은 VSIX에 다른 구성 요소를 포함할 수 있습니다.
VSIX 프로젝트에 별도의 메뉴 명령을 추가하려면
자체 VSIX가 있는 메뉴 명령을 만든 경우 이 절차가 필요 없습니다.
솔루션에 VSIX 프로젝트가 이미 있는 경우가 아니면 새로 만듭니다.
솔루션 탐색기에서 솔루션을 마우스 오른쪽 단추로 클릭하고 추가를 가리킨 다음, 새 프로젝트를 클릭합니다.
설치된 템플릿에서 Visual C# 또는 Visual Basic을 확장한 다음, 확장성을 클릭합니다. 가운데 열에서 VSIX 프로젝트를 클릭합니다.
VSIX 프로젝트를 솔루션의 시작 프로젝트로 설정합니다.
솔루션 탐색기에서 VSIX 프로젝트를 마우스 오른쪽 단추로 클릭하고 시작 프로젝트로 설정을 클릭합니다.
source.extension.vsixmanifest의 콘텐츠에서 클래스 라이브러리 프로젝트를 MEF 구성 요소로 추가합니다.
source.extension.vsixmanifest를 엽니다.
콘텐츠 추가를 클릭합니다.
콘텐츠 형식 선택에서 MEF 구성 요소를 선택합니다.
소스 선택에서 프로젝트를 클릭하고 클래스 라이브러리 프로젝트의 이름을 선택합니다.
버전 선택을 클릭한 다음, 확장을 실행할 대상 Visual Studio 버전을 선택합니다.
VSIX의 이름 및 설명 필드를 설정합니다. 파일을 저장합니다.
메뉴 명령 구현
메뉴 명령 클래스는 ICommandExtension의 필수 메서드를 구현합니다.
string Text { get; } |
메뉴 항목의 레이블을 반환합니다. |
void QueryStatus(IMenuCommand command); |
사용자가 다이어그램에서 마우스 오른쪽 단추를 클릭하면 호출됩니다. 이 메서드는 모델을 변경하면 안 됩니다. DiagramContext.CurrentDiagram.SelectedShapes를 사용하면 명령을 나타내고 사용 가능하게 설정할지 여부를 결정할 수 있습니다. 다음과 같이 설정합니다.
|
void Execute (IMenuCommand command); |
메뉴에 표시되고 사용 가능하도록 설정된 메뉴 항목을 사용자가 클릭하면 호출됩니다.
|
코드에서 모델에 액세스
메뉴 명령 클래스에 다음 선언을 포함합니다.
[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 (IElement element in modelStore.AllInstances<IUseCase>()) {...}
모델 탐색 및 업데이트
UML 모델의 요소는 모두 API를 통해 사용할 수 있습니다. 현재 선택 항목이나 모델의 루트에서 다른 모든 요소에 액세스할 수 있습니다. 자세한 내용은 방법: UML 모델 탐색 및 UML API를 사용한 프로그래밍을 참조하십시오.
시퀀스 다이어그램을 처리하는 경우에는 방법: UML API를 사용하여 시퀀스 다이어그램 편집을 참조하십시오.
API를 통해 요소의 속성을 변경하거나, 요소 및 관계를 삭제하거나, 새 요소 및 관계를 만들 수도 있습니다.
기본적으로 Execute 메서드에서의 각 변경 내용은 개별 트랜잭션에서 수행됩니다. 따라서 사용자가 각 변경 내용을 개별적으로 취소할 수 있습니다. 변경 내용을 단일 트랜잭션으로 그룹화하려면 방법: 트랜잭션을 사용하여 모델 업데이트 연결에 설명된 대로 ILinkedUndoTransaction을 사용합니다.
업데이트를 위해 UI 스레드 사용
경우에 따라 백그라운드 스레드에서 모델을 업데이트하면 유용할 때가 있습니다. 예를 들어 속도가 느린 리소스에서 데이터를 로드하는 명령의 경우 백그라운드 스레드에서 로드를 수행하면 사용자는 변경이 진행되는 동안 해당 내용을 확인하고 필요에 따라 작업을 취소할 수 있습니다.
그러나 모델 저장소는 스레드로부터 안전하지 않다는 사실을 잘 알고 있어야 합니다. 업데이트를 수행할 때는 항상 UI(사용자 인터페이스) 스레드를 사용해야 하며 가능하면 백그라운드 작업이 진행 중인 동안에는 사용자가 편집하지 않도록 해야 합니다. 예제를 보려면 방법: 백그라운드 스레드에서 UML 모델 업데이트을 참조하십시오.
메뉴 명령 실행
테스트 목적으로 디버그 모드에서 명령을 실행합니다.
메뉴 명령을 테스트하려면
F5 키를 누르거나, 디버그 메뉴에서 디버깅 시작을 클릭합니다.
실험적 Visual Studio 인스턴스가 시작됩니다.
문제 해결: 새 Visual Studio가 시작되지 않는 경우:
하나 이상의 프로젝트가 있는 경우 VSIX 프로젝트가 솔루션의 시작 프로젝트로 설정되어 있는지 확인하십시오.
솔루션 탐색기에서 시작 또는 프로젝트만 마우스 오른쪽 단추로 클릭하고 속성을 클릭합니다. 프로젝트 속성 편집기에서 디버그 탭을 클릭합니다. 시작 외부 프로그램 필드의 문자열이 대개 다음과 같은 Visual Studio의 전체 경로 이름인지 확인합니다.
C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe
실험적 Visual Studio에서 모델링 프로젝트 및 모델링 다이어그램을 열거나 만듭니다. 메뉴 명령 클래스의 특성에 나열된 형식 중 하나에 속하는 다이어그램을 사용하십시오.
다이어그램에서 아무 곳이나 마우스 오른쪽 단추를 클릭합니다. 그러면 메뉴에 명령이 나타납니다.
문제 해결: 메뉴에 명령이 나타나지 않으면 다음을 검토하십시오.
메뉴 명령 프로젝트가 VSIX 프로젝트의 source.extensions.manifest에서 콘텐츠 목록에 MEF 구성 요소로 나열되어 있는지 확인합니다.
Import 및 Export 특성의 매개 변수가 올바른지 확인합니다.
QueryStatus 메서드의 command.Enabled 또는 Visible 필드가 false로 설정되어 있지 않은지 확인합니다.
UML 클래스와 시퀀스 다이어그램 등 사용하는 모델 다이어그램의 형식이 [ClassDesignerExtension], [SequenceDesignerExtension] 등의 메뉴 명령 클래스 특성 중 하나로 나열되어 있는지 확인합니다.
확장 설치 및 제거
자신이 사용하는 컴퓨터와 다른 컴퓨터에 둘 다 Visual Studio 확장을 설치할 수 있습니다.
확장을 설치하려면
컴퓨터에서 VSIX 프로젝트에 의해 빌드된 .vsix 파일을 찾습니다.
솔루션 탐색기에서 VSIX 프로젝트를 마우스 오른쪽 단추로 클릭하고 Windows 탐색기에서 폴더 열기를 클릭합니다.
bin\*\YourProject.vsix 파일을 찾습니다.
확장을 설치할 대상 컴퓨터에 .vsix 파일을 복사합니다. 대상 컴퓨터는 현재 사용 중인 컴퓨터일 수도 있고 다른 컴퓨터일 수도 있습니다.
대상 컴퓨터에는 source.extension.vsixmanifest에 지정한 Visual Studio 버전 중 하나가 있어야 합니다.
대상 컴퓨터에서 .vsix 파일을 두 번 클릭합니다.
Visual Studio Extension 설치 관리자가 열리고 확장이 설치됩니다.
Visual Studio를 시작하거나 다시 시작합니다.
확장을 제거하려면
도구 메뉴에서 확장 관리자를 클릭합니다.
설치된 확장을 확장합니다.
확장을 선택하고 제거를 클릭합니다.
드물기는 하지만 잘못된 확장은 로드되지 않으며 오류 창에 보고서가 만들어지지만 확장 관리자에는 나타나지 않습니다. 이 경우에는 다음 위치에서 파일을 삭제하여 확장을 제거할 수 있습니다.
%LocalAppData%\Local\Microsoft\VisualStudio\10.0\Extensions
예제
다음 예제에서는 클래스 다이어그램에 있는 두 요소의 이름을 서로 바꾸는 메뉴 명령의 코드를 보여 줍니다. 이 코드는 이전 단원에서 설명한 대로 Visual Studio Extension 프로젝트에 빌드된 후 설치되어야 합니다.
using System.Collections.Generic; // for IEnumerable
using System.ComponentModel.Composition;
// for [Import], [Export]
using System.Linq; // for IEnumerable extensions
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
// for IDiagramContext
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
// for designer extension attributes
using Microsoft.VisualStudio.Modeling.Diagrams;
// for ShapeElement
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
// for IGestureExtension, ICommandExtension, ILinkedUndoContext
using Microsoft.VisualStudio.Uml.Classes;
// for class diagrams, packages
/// <summary>
/// Extension to swap names of classes in a class diagram.
/// </summary>
namespace SwapClassNames
{
// Declare the class as an MEF component:
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension]
// Add more ExportMetadata attributes to make
// the command appear on diagrams of other types.
public class NameSwapper : ICommandExtension
{
// MEF required interfaces:
[Import]
public IDiagramContext Context { get; set; }
[Import]
public ILinkedUndoContext LinkedUndoContext { get; set; }
/// <summary>
/// Swap the names of the currently selected elements.
/// </summary>
/// <param name="command"></param>
public void Execute(IMenuCommand command)
{
// Get selected shapes that are IClassifiers -
// IClasses, IInterfaces, IEnumerators.
var selectedShapes = Context.CurrentDiagram
.GetSelectedShapes<IClassifier>();
if (selectedShapes.Count() < 2) return;
// Get model elements displayed by shapes.
IClassifier firstElement = selectedShapes.First().Element;
IClassifier lastElement = selectedShapes.Last().Element;
// Do the swap in a transaction so that user
// cannot undo one change without the other.
using (ILinkedUndoTransaction transaction =
LinkedUndoContext.BeginTransaction("Swap names"))
{
string firstName = firstElement.Name;
firstElement.Name = lastElement.Name;
lastElement.Name = firstName;
transaction.Commit();
}
}
/// <summary>
/// Called by Visual Studio to determine whether
/// menu item should be visible and enabled.
/// </summary>
public void QueryStatus(IMenuCommand command)
{
int selectedClassifiers = Context.CurrentDiagram
.GetSelectedShapes<IClassifier>().Count();
command.Visible = selectedClassifiers > 0;
command.Enabled = selectedClassifiers == 2;
}
/// <summary>
/// Name of the menu command.
/// </summary>
public string Text
{
get { return "Swap Names"; }
}
}
}
참고 항목
개념
방법: UML 모델에 대한 유효성 검사 제약 조건 정의
기타 리소스
방법: 모델링 다이어그램에서 끌어서 놓기 또는 두 번 클릭 처리기 정의