방법: 백그라운드 스레드에서 UML 모델 업데이트
경우에 따라 백그라운드 스레드에서 모델을 변경하면 유용할 때가 있습니다. 예를 들어 속도가 느린 외부 리소스에서 정보를 로드하는 경우 백그라운드 스레드를 사용하여 업데이트를 감독할 수 있습니다. 이렇게 하면 각 업데이트가 발생할 때마다 사용자가 바로 확인할 수 있습니다.
그러나 UML 저장소는 스레드로부터 안전하지 않다는 사실을 잘 알고 있어야 합니다. 따라서 다음과 같은 사전 조치가 중요합니다.
모델이나 다이어그램에 대한 모든 업데이트는 UI(사용자 인터페이스) 스레드에서 수행되어야 합니다. 백그라운드 스레드는 Invoke 또는 Invoke``1를 사용하여 UI 스레드에서 실제 업데이트를 수행하도록 해야 합니다.
일련의 변경 내용을 단일 트랜잭션으로 그룹화하는 경우 트랜잭션이 진행되는 동안 사용자가 모델을 편집할 수 없도록 하는 것이 좋습니다. 그렇지 않으면 사용자가 편집한 모든 내용이 같은 트랜잭션의 일부로 포함됩니다. 모달 대화 상자를 표시하여 사용자가 변경할 수 없도록 할 수 있습니다. 원하는 경우 대화 상자에 취소 단추를 제공할 수 있습니다. 사용자가는 변경하는 즉시 내용을 확인할 수 있습니다.
예제
이 예제에서는 백그라운드 스레드를 사용하여 모델에서 몇 가지 내용을 변경합니다. 여기에서는 스레드가 실행되는 동안 사용자를 제외하기 위해 대화 상자가 사용됩니다. 간단한 이 예제에서는 대화 상자에 취소 단추가 제공되지 않습니다. 그러나 해당 기능을 쉽게 추가할 수 있습니다.
예제를 실행하려면
방법: 모델링 다이어그램의 메뉴 명령 정의에서 설명한 대로 C# 프로젝트에 명령 처리기를 만듭니다.
프로젝트에 다음과 같은 어셈블리에 대한 참조가 포함되도록 합니다.
Microsoft.VisualStudio.ArchitectureTools.Extensibility
Microsoft.VisualStudio.Modeling.Sdk.12.0
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.12.0
Microsoft.VisualStudio.Uml.Interfaces
System.ComponentModel.Composition
System.Windows.Forms
ProgressForm이라는 Windows form을 프로젝트에 추가합니다. 이 폼에는 업데이트가 진행되고 있음을 나타내는 메시지가 표시되어야 하며, 다른 컨트롤은 포함할 필요가 없습니다.
7단계 이후에 표시된 코드를 포함하는 C# 파일을 추가합니다.
프로젝트를 빌드하고 실행합니다.
Visual Studio의 새 인스턴스가 실험 모드에서 시작됩니다.
실험적 Visual Studio의 인스턴스에서 UML 클래스 다이어그램을 만들거나 엽니다.
UML 클래스 다이어그램의 아무 곳이나 마우스 오른쪽 단추로 클릭하고 여러 UML 클래스 추가를 클릭합니다.
0.5초의 간격으로 몇 개의 새 클래스 상자가 차례로 다이어그램에 나타납니다.
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.Uml.Classes;
namespace BackgroundThreadProgressUI // CHANGE TO YOUR NAMESPACE
{
[Export(typeof(ICommandExtension))]
[ClassDesignerExtension]
class UmlClassAdderCommand : ICommandExtension
{
[Import]
IDiagramContext context { get; set; }
[Import]
ILinkedUndoContext linkedUndoContext { get; set; }
// Called when the user runs the command.
public void Execute(IMenuCommand command)
{
// The form that will exclude the user.
ProgressForm form = new ProgressForm();
// System.ComponentModel.BackgroundWorker is a
// convenient way to run a background thread.
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += delegate(object sender, DoWorkEventArgs args)
{
// This block will be executed in a background thread.
IClassDiagram diagram = context.CurrentDiagram as IClassDiagram;
IModelStore store = diagram.ModelStore;
const int CLASSES_TO_CREATE = 15;
// Group all the changes together.
using (ILinkedUndoTransaction transaction = linkedUndoContext.BeginTransaction("Background Updates"))
{
for (int i = 1; i < CLASSES_TO_CREATE; i++)
{
if (worker.CancellationPending)
return; // No commit - undo all.
// Create model elements using the UI thread by using
// the Invoke method on the progress form. Always
// modify the model and diagrams from a UI thread.
form.Invoke((MethodInvoker)(delegate
{
IClass newClass = store.Root.CreateClass();
newClass.Name = string.Format("NewClass{0}", i);
diagram.Display(newClass);
}));
// Sleep briefly so that we can watch the updates.
Thread.Sleep(500);
}
// Commit the transaction or it will be rolled back.
transaction.Commit();
}
};
// Close the form when the thread completes.
worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs args)
{
form.Close();
};
// Start the thread before showing the modal progress dialog.
worker.RunWorkerAsync();
// Show the form modally, parented on VS.
// Prevents the user from making changes while in progress.
form.ShowDialog();
}
public void QueryStatus(IMenuCommand command)
{
command.Enabled = command.Visible = true;
}
public string Text
{
get { return "Add several classes"; }
}
}
}
사용자가 예제에서 스레드를 취소할 수 있도록 하려면
진행률 대화 상자에 취소 단추를 추가합니다.
진행률 대화 상자에 다음 코드를 추가합니다.
public event MethodInvoker Cancel;
private void CancelButton_Click(object sender, EventArgs e)
{
Cancel();
}
Execute() 메서드에서 폼 생성 뒤에 다음 줄을 삽입합니다.
form.Cancel += delegate() { worker.CancelAsync(); };
UI 스레드 액세스를 위한 다른 메서드
대화 상자를 만들지 않으려면 다음과 같이 다이어그램을 표시하는 컨트롤에 액세스할 수 있습니다.
DiagramView uiThreadHolder = context.CurrentDiagram.GetObject<Diagram>().ActiveDiagramView;
uiThreadHolder.Invoke()를 사용하여 UI 스레드에서 작업을 수행할 수 있습니다.