Como atualizar um modelo UM a partir de um thread em segundo plano
Em alguns casos, pode ser útil fazer alterações em um modelo em um segmento de plano de fundo. Por exemplo, se você estiver carregando informações de um recurso externo lento, você pode usar um segmento em segundo plano para supervisionar as atualizações. Isso permite que o usuário veja cada atualização assim que ela acontece.
Entretanto, você deve estar ciente que o armazenamento de UML não tem segurança de segmentos. As seguintes precauções são importantes:
Cada atualização para um modelo ou diagrama deve ser feita no segmento de (UI) interface do usuário. O thread em segundo plano deve usar Invoke ou Invoke``1 para fazer com que o thread de interface do usuário execute as atualizações reais.
Se você agrupar uma série de alterações em uma única transação, recomendamos que você impeça o usuário de editar o modelo quando a transação estiver em andamento. Do contrário, todas as edições feitas pelo usuário se tornarão parte da mesma transação. Você pode impedir que o usuário faça alterações mostrando uma caixa de diálogo modal. Se você desejar, você pode fornecer um botão Cancelar na caixa de diálogo. O usuário pode ver as alterações assim que elas ocorrem.
Exemplo
Esse exemplo usa uma thread em segundo plano para fazer várias alterações em um modelo. Uma caixa de diálogo é usada para excluir o usuário quando o thread é executado. Nesse exemplo simples, nenhum botão Cancelar é fornecido na caixa de diálogo. No entanto, é fácil adicionar esse recurso.
Para executar o exemplo
Crie um manipulador de comando em um projeto do C# como descrito em Como definir um comando de menu em um diagrama de modelagem.
Certifique-se de que o projeto inclua referências a esses assemblies:
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
Adicione ao projeto um formulário do Windows chamado ProgressForm. Deve exibir uma mensagem informando que as atualizações estão em andamento. Não precisa ter quaisquer outros controles.
Adicione um arquivo C# que contém o código mostrado após a etapa 7.
Criar e executar o projeto.
Uma nova instância de Visual Studio será iniciada no modo experimental.
Crie ou abra um diagrama de classe de UML na instância de avaliação do Visual Studio.
Clique com o botão direito do mouse em qualquer lugar no diagrama de classe UML e clique em Adicionar Várias Classes de UML.
Várias novas caixas de classes aparecerão no diagrama, uma após a outra em intervalos de meio segundo.
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"; }
}
}
}
Para permitir que o usuário cancele o thread no exemplo
Adicione um botão Cancelar à caixa de diálogo de progresso.
Adicione o seguinte código à caixa de diálogo de progresso:
public event MethodInvoker Cancel;
private void CancelButton_Click(object sender, EventArgs e)
{
Cancel();
}
No método Execute() , insira essa linha após a compilação do formulário:
form.Cancel += delegate() { worker.CancelAsync(); };
Outros métodos de acesso ao thread de interface de usuário
Se você não desejar criar uma caixa de diálogo, você poderá acessar o controle que exibe o diagrama:
DiagramView uiThreadHolder = context.CurrentDiagram.GetObject<Diagram>().ActiveDiagramView;
Você pode usar uiThreadHolder.Invoke() para executar operações no thread de interface de usuário.
Consulte também
Conceitos
Como definir um comando de menu em um diagrama de modelagem
Como definir um manipulador de gesto em um diagrama de modelagem