Como: atualizar um modelo UML a partir de um Thread de plano de fundo

Às vezes pode ser útil fazer alterações a um modelo em um segmento de plano de fundo.Por exemplo, se você está carregando informações de um recurso externo lento, você pode usar uma thread em segundo plano para supervisionar atualizações.Isso permite que o usuário possa ver cada atualização para o que 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 um diagrama deve ser feita no encadeamento de interface do usuário.O thread em segundo plano deve usar Invoke ou Invoke para que o encadeamento de interface do usuário executar atualizações reais.

  • Se você agrupa uma série de alterações em uma única transação, recomendamos que você impede que o usuário edite o modelo quando a transação está em andamento.Se não, todas edições feitas pelo usuário tornar-se-ã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 que ocorrem.

Exemplo

Este exemplo usa uma thread em segundo plano para fazer várias alterações a um modelo.Uma caixa de diálogo é usada para excluir o usuário quando o segmento executar.Nesse exemplo simples, nenhum botão cancelar é fornecido na caixa de diálogo.No entanto, é fácil adicionar esse recurso.

Para executar o exemplo

  1. Crie um manipulador de comando em um projeto C# como descrito em Como: definir um comando de Menu em um diagrama de modelagem.

  2. Certifique-se que o projeto inclui referências a esses assemblies:

    • Microsoft.VisualStudio.ArchitectureTools.Extensibility

    • Microsoft.VisualStudio.Modeling.Sdk.11.0

    • Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0

    • Microsoft.VisualStudio.Uml.Interfaces

    • System.ComponentModel.Composition

    • System.Windows.Forms

  3. Adicione ao projeto um formulário do Windows chamado ProgressForm.Deve exibir uma mensagem que estados que as atualizações são em andamento.Não precisa ter quaisquer outros controles.

  4. Adicionar um arquivo C# que contém o código que é mostrado após a etapa 7.

  5. Criar e executar o projeto.

    Uma nova instância de Visual Studio começará no modo de avaliação.

  6. Crie ou abra um diagrama de classe de UML na instância de avaliação de Visual Studio.

  7. Clique com o botão direito do mouse em qualquer lugar no diagrama de classe de UML e clique em Adicionar várias classes de UML.

Várias novas caixas da classe aparecerão no diagrama, um após o outro em intervalos de um meio segundos.

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 segmento no exemplo

  1. Adicione um botão cancelar a caixa de diálogo de progresso.

  2. Adicione o seguinte código à caixa de diálogo de progresso:

    public event MethodInvoker Cancel;

    private void CancelButton_Click(object sender, EventArgs e)

    {

    Cancel();

    }

  3. No método de Execute() , inserir essa linha após a compilação do formulário:

    form.Cancel += delegate() { worker.CancelAsync(); };

Ee941659.collapse_all(pt-br,VS.110).gifOutros métodos para acessar o encadeamento de interface de usuário

Se você não deseja criar uma caixa de diálogo, você pode acessar o controle que exibe o diagrama:

DiagramView uiThreadHolder = context.CurrentDiagram.GetObject<Diagram>().ActiveDiagramView;

Você pode usar uiThreadHolder.Invoke() para executar operações no encadeamento de interface do 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