Sdílet prostřednictvím


Postupy: Aktualizace modelu UML z vlákna na pozadí

Někdy může být užitečné provést změny v modelu ve vlákně na pozadí.Například pokud načítáte informace z pomalého externího zdroje, můžete použít vlákno na pozadí k dohledu nad aktualizacemi.To umožňuje uživatelům zobrazit každou aktualizaci ihned, jakmile k ní dojde.

Musí si však být vědomi, že úložiště UML není bezpečné pro vlákna.Důležitá jsou následující opatření:

  • Všechny aktualizace modelu nebo diagramu se musí provádět ve vlákně uživatelského rozhraní (UI).Vlákno na pozadí musíte používat Invoke nebo Invoke``1, aby vlákno uživatelského rozhraní provedlo skutečné aktualizace.

  • Pokud seskupíte řady změn do jediné transakce, doporučujeme zabránit uživateli v úpravě modelu, když transakce probíhá.Jinak se veškeré úpravy provedené uživatelem stanou součástí stejné transakce.Uživateli můžete zabránit v provádění změn tím zobrazením modálního dialogového okna.Pokud chcete, můžete zadat tlačítko Storno v dialogovém okně.Uživatel můžete zobrazit změny při jejich provádění.

Příklad

Tento příklad využívá vlákno na pozadí pro provedení několika změn v modelu.Dialogové okno se používá k vyloučení uživatele, když je spuštěn podproces.V tomto jednoduchém příkladu není v dialogovém okně k dispozici žádné tlačítko Storno.Nicméně by bylo možné snadno přidat funkci.

Spuštění příkladu

  1. Vytvořte obslužnou rutinu pro příkaz v projektu jazyka C#, jak je popsáno v Postupy: Definování příkazu nabídky v diagramu modelování.

  2. Ujistěte se, že projekt obsahuje odkazy na tato sestavení:

    • 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. Do projektu přidáte formulář pro systém Windows s názvem ProgressForm.Měla by se zobrazit zpráva oznamující, že probíhají aktualizace.Nepotřebuje mít žádné další ovládací prvky.

  4. Přidejte soubor jazyka C#, který obsahuje kód, který se zobrazí po provedení kroku 7.

  5. Sestavte a spusťte projekt.

    Nová instance Visual Studio začne v experimentálním režimu.

  6. Vytvořte nebo otevřete diagram tříd UML v experimentální instanci sady Visual Studio.

  7. Klepněte pravým tlačítkem myši kamkoliv v diagramu tříd UML a potom klepněte na tlačítko Přidat několik tříd UML.

Několik nových polí tříd se zobrazí v diagramu, jeden po druhém v intervalech půl 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"; }
    }
  }
}

Umožnění uživateli zrušit vlákno v tomto příkladu

  1. Přidejte tlačítko Storno do dialogového okna průběhu.

  2. Následující kód přidejte do dialogového okna průběhu:

    public event MethodInvoker Cancel;

    private void CancelButton_Click(object sender, EventArgs e)

    {

    Cancel();

    }

  3. Metoda Execute() vloží tento řádek po konstrukci formuláře:

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

Jiné metody přístupu k vláknu uživatelského rozhraní

Pokud nechcete vytvořit dialogové okno, můžete přejít k ovládacímu prvku, který zobrazuje diagram:

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

Můžete použít uiThreadHolder.Invoke() k provedení operací ve vlákně UI.

Viz také

Koncepty

Postupy: Definování příkazu nabídky v diagramu modelování

Postupy: Definování obslužné rutiny gest v diagramu modelování