방법: 트랜잭션을 사용하여 모델 업데이트 연결
Visual Studio Ultimate에서 UML 디자이너에 대한 확장을 정의하는 경우 여러 변경 내용을 연결된 실행 취소 컨텍스트라는 단일 트랜잭션으로 그룹화할 수 있습니다.
기본적으로 코드에서 모델에 대해 변경하는 각 내용은 사용자가 개별적으로 실행 취소할 수 있습니다. 예를 들어 두 UML 클래스의 이름을 서로 바꾸는 메뉴 명령을 정의하는 경우 사용자가 이 명령을 호출한 후 단일 실행 취소를 수행할 수 있습니다. 이렇게 하면 한 이름에 대한 변경 내용만 실행 취소되고 다른 이름은 취소되지 않으므로 모델은 의도하지 않은 상태가 됩니다.
이런 문제가 발생하지 않도록 하기 위해 코드에서 일련의 변경 내용을 하나의 트랜잭션 내에서 수행할 수 있습니다. 이렇게 하면 사용자는 단일 변경 내용으로 인식하게 됩니다. 이후 실행 취소 명령을 수행하면 전체 변경 내용이 실행 취소됩니다.
또한 예외를 throw하거나 트랜잭션을 중단하여 전체 변경 내용 집합을 부분적으로 실행 취소할 수 있다는 이점도 있습니다.
변경 내용을 단일 트랜잭션으로 그룹화하려면
프로젝트 참조에 다음 .NET 어셈블리가 포함되어야 합니다.
Microsoft.VisualStudio.Modeling.Sdk.12.0.dll
다음과 같이 클래스 내에서 ILinkedUndoContext 형식의 가져온 속성을 선언합니다.
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
...
class … {
[Import]
public ILinkedUndoContext LinkedUndoContext { get; set; }
다음과 같이 모델을 수정하는 메서드에서 변경 내용을 트랜잭션에 포함합니다.
using (ILinkedUndoTransaction transaction =
LinkedUndoContext.BeginTransaction("my updates"))
{
// code to update model elements or shapes goes here
transaction.Commit();
}
다음 내용을 참고하십시오.
트랜잭션의 끝에 항상 Commit()을 포함해야 합니다. 트랜잭션을 커밋하지 않고 삭제하면 해당 트랜잭션이 롤백됩니다. 즉, 트랜잭션을 시작할 때의 상태로 모델이 복원됩니다.
트랜잭션 내에서 catch되지 않은 예외가 발생하면 해당 트랜잭션이 롤백됩니다. 트랜잭션의 using 블록을 try…catch 블록 내에 포함하는 것은 자주 사용되는 패턴입니다.
트랜잭션을 중첩시킬 수 있습니다.
공백이 아닌 이름을 BeginTransaction()에 제공할 수 있습니다.
UML 모델 저장소만 이러한 트랜잭션의 영향을 받습니다. 모델링 트랜잭션은 변수, 외부 저장소(예: 파일과 데이터베이스), 레이어 다이어그램, 코드에서 생성된 시퀀스 다이어그램 및 코드 모델에 영향을 주지 않습니다.
예제
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.Uml.Interfaces;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Extensions;
using System.Linq;
using System.ComponentModel.Composition;
...
[Import]
public ILinkedUndoContext LinkedUndoContext { get; set; }
/// <summary>
/// Swap the names of the currently selected elements.
/// </summary>
public void Execute(IMenuCommand command)
{
var selectedShapes =
Context.CurrentDiagram.GetSelectedShapes<IClassifier>();
if (selectedShapes.Count() < 2) return;
IClassifier firstElement = selectedShapes.First().Element;
IClassifier lastElement = selectedShapes.Last().Element;
string firstName = firstElement.Name;
// Perform changes inside a transaction so that undo
// works as a single change.
using (ILinkedUndoTransaction transaction =
LinkedUndoContext.BeginTransaction("Swap names"))
{
firstElement.Name = lastElement.Name;
lastElement.Name = firstName;
transaction.Commit();
}
}