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
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í.
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
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.
Přidejte soubor jazyka C#, který obsahuje kód, který se zobrazí po provedení kroku 7.
Sestavte a spusťte projekt.
Nová instance Visual Studio začne v experimentálním režimu.
Vytvořte nebo otevřete diagram tříd UML v experimentální instanci sady Visual Studio.
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
Přidejte tlačítko Storno do dialogového okna průběhu.
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();
}
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í