Udostępnij za pośrednictwem


Porady: aktualizowanie modelu UML z wątku w tle

Czasami może być przydatny do wprowadzania zmian w modelu w wątku tła.Na przykład, w przypadku ładowania informacji z powolnego zewnętrznego zasobu, można użyć wątku tła do nadzorowania aktualizacji.To pozwala użytkownikowi oglądać każdą aktualizację, tak szybko, jak to się dzieje.

Należy jednak pamiętać, że magazyn UML nie jest bezpieczny dla wątków.Ważne są następujące środki ostrożności:

  • Każda aktualizacji modelu lub diagramu musi nastąpić w wątku interfejsu użytkownika (UI).Wątek tła musi użyć Invoke lub Invoke``1, aby sprawić, że wątek interfejsu użytkownika wykona bieżące aktualizacje.

  • Jeśli grupujesz serie zmian w pojedynczą transakcję, firma Microsoft zaleca uniemożliwienie użytkownikowi edytowanie modelu, gdy transakcja jest w toku.W przeciwnym razie zmiany wprowadzone przez użytkownika staną się częścią tej samej transakcji.Możesz uniemożliwić użytkownikowi dokonywanie zmian poprzez wyświetlenie modalnego okna dialogowego.Jeśli chcesz, możesz dostarczyć przycisk Anuluj w oknie dialogowym.Użytkownik może wyświetlić zmiany po ich wprowadzeniu.

Przykład

W tym przykładzie użyto wątku tła, aby wprowadzić wiele zmian do modelu.Okno dialogowe służy do wykluczenia użytkownika, podczas gdy wątek jest uruchomiony.W tym prostym przykładzie brak przycisku Anuluj w oknie dialogowym.Jednakże może być łatwo dodać tę funkcję.

Aby uruchomić przykład

  1. Utwórz procedurę obsługi poleceń w projekcie języka C# w sposób opisany w Porady: definiowanie polecenia menu na diagramie modelowania.

  2. Upewnij się, że projekt zawiera odwołania do tych zestawów:

    • 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

  3. Dodaj do projektu formularz systemu Windows o nazwie ProgressForm.Powinien wyświetlić komunikat informujący, że aktualizacje są w toku.Nie musi mieć żadnych innych formantów.

  4. Dodaj plik języka C#, który zawiera kod wyświetlany po kroku 7.

  5. Skompiluj i uruchom projekt.

    Nowe wystąpienie Visual Studio będzie uruchomione w trybie doświadczalnym.

  6. Utwórz lub otwórz diagram klasy UML w instancji doświadczalnej Visual Studio.

  7. Kliknij prawym przyciskiem myszy diagram klas UML, a następnie kliknij przycisk Dodaj kilka klas UML.

Kilka nowych pól klasy pojawi się w diagramie, po kolei w odstępach co pół sekundy.

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"; }
    }
  }
}

Aby zezwolić użytkownikowi anulowanie wątku w przykładzie

  1. Dodaj przycisk Anuluj do okna dialogowego postępu.

  2. Dodaj następujący kod do okna dialogowego postępu:

    public event MethodInvoker Cancel;

    private void CancelButton_Click(object sender, EventArgs e)

    {

    Cancel();

    }

  3. W metodzie Execute() wstaw ten wiersz po zbudowaniu formularza:

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

Inne metody dostępu do wątku interfejsu użytkownika

Jeśli chcesz utworzyć okno dialogowe, można uzyskać dostęp do formantu, który wyświetla diagram:

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

Można użyć uiThreadHolder.Invoke() do wykonywania operacji w wątku interfejsu użytkownika.

Zobacz też

Koncepcje

Porady: definiowanie polecenia menu na diagramie modelowania

Porady: definiowanie procedury obsługi gestów na diagramie modelowania