Gewusst wie: Definieren eines Gestenhandlers in einem Modellierungsdiagramm
In Visual Studio Ultimate können Sie Befehle definieren, die ausgeführt werden, wenn Benutzer auf Elemente doppelklicken oder Elemente in ein UML-Diagramm ziehen.Sie können diese Erweiterungen in eine Visual Studio-Integrationserweiterung (VSIX) verpacken und an andere Visual Studio Ultimate-Benutzern verteilen.
Wenn bereits ein integriertes Verhalten für den Diagrammtyp und den Elementtyp vorhanden ist, das gezogen werden soll, können Sie dieses Verhalten möglicherweise nicht hinzufügen oder überschreiben.
Anforderungen
Visual Studio SDK, dem Sie abrufen können Visual Studio Gallery.
Visual Studio-Visualisierungs-undModellierungs-SDK, dem Sie abrufen können. Visual Studio-Visualisierungs-undModellierungs-SDK auf der Code Gallery
Erstellen eines Gestenhandlers
Um für einen UML-Designer einen Gestenhandler zu definieren, müssen Sie eine Klasse erstellen, die das Verhalten des Gestenhandlers definiert, und diese Klasse in eine Visual Studio-Integrationserweiterung (VSIX) einbetten.Die VSIX fungiert als Container, der den Handler installieren kann.Es gibt zwei alternative Methoden, um einen Gestenhandler zu definieren:
Erstellen Sie mithilfe einer Projektvorlage einen Gestenhandler in seiner eigenen VSIX. Dies ist die schnellere Methode.Verwenden Sie diese, wenn Sie den Handler nicht mit anderen Erweiterungstypen, z. B. Validierungserweiterungen, benutzerdefinierten Toolboxelementen oder Menübefehlen, kombinieren möchten.
Erstellen Sie separate Gestenhandler und VSIX-Projekte. Verwenden Sie diese Methode, wenn Sie mehrere Erweiterungstypen in dieselbe VSIX kombinieren möchten.Wenn beispielsweise der Gestenhandler erwartet, dass das Modell bestimmte Einschränkungen berücksichtigt, können Sie es in dieselbe VSIX wie eine Validierungsmethode einbetten.
So erstellen Sie einen Gestenhandler in seiner eigenen VSIX
Klicken Sie im Dialogfeld Neues Projekt unter Modellierungsprojekte auf Gestenerweiterung.
Öffnen Sie die .cs-Datei im neuen Projekt, und ändern Sie die GestureExtension-Klasse, um den Gestenhandler zu implementieren.
Weitere Informationen finden Sie unter Implementieren des Gestenhandlers.
Testen Sie den Gestenhandler durch Drücken von F5.Weitere Informationen finden Sie unter Ausführen des Gestenhandlers.
Installieren Sie den Gestenhandler auf einem anderen Computer, indem Sie die vom Projekt erstellte Datei bin\*\*.vsix kopieren.Weitere Informationen finden Sie unter Installieren des Gestenhandlers.
Hier ist das Ausweichverfahren:
So fügen Sie ein separates Klassenbibliotheksprojekt (DLL) für den Gestenhandler erstellen
Erstellen Sie in einer neuen Visual Studio-Projektmappe oder in einer vorhandenen Projektmappe ein Klassenbibliotheksprojekt.
Wählen Sie im Menü Datei die Optionsfolge Neu, Projekt aus.
Erweitern Sie unter Installierte VorlagenVisual C# oder Visual Basic, anschließend in der mittleren Spalte wählen Sie Klassenbibliothek aus.
Fügen Sie dem Projekt die folgenden Verweise hinzu.
Microsoft.VisualStudio.Modeling.Sdk.11.0
Microsoft.VisualStudio.Modeling.Sdk.Diagrams.11.0
Microsoft.VisualStudio.ArchitectureTools.Extensibility
Microsoft.VisualStudio.Uml.Interfaces
System.ComponentModel.Composition
System.Windows.Forms
Microsoft.VisualStudio.ArchitectureTools.Extensibility.Layer – Dies ist nur erforderlich, wenn Sie Ebenendiagramme erweitern.Weitere Informationen finden Sie unter Erweitern von Ebenendiagrammen.
Fügen Sie dem Projekt eine Klassendatei hinzu, und legen Sie deren Inhalt auf den folgenden Code fest.
Hinweis Ändern Sie die Namespace- und Klassennamen entsprechend den jeweiligen Anforderungen.
using System.ComponentModel.Composition; using System.Linq; using System.Collections.Generic; using Microsoft.VisualStudio.Modeling.Diagrams; using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement; using Microsoft.VisualStudio.Modeling.ExtensionEnablement; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml; using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation; using Microsoft.VisualStudio.Uml.AuxiliaryConstructs; using Microsoft.VisualStudio.Modeling; using Microsoft.VisualStudio.Uml.Classes; // ADD other UML namespaces if required namespace MyGestureHandler // CHANGE { // DELETE any of these attributes if the handler // should not work with some types of diagram. [ClassDesignerExtension] [ActivityDesignerExtension] [ComponentDesignerExtension] [SequenceDesignerExtension] [UseCaseDesignerExtension] // [LayerDesignerExtension] // Gesture handlers must export IGestureExtension: [Export(typeof(IGestureExtension))] // CHANGE class name public class MyGesture1 : IGestureExtension { [Import] public IDiagramContext DiagramContext { get; set; } /// <summary> /// Called when the user double-clicks on the diagram /// </summary> /// <param name="targetElement"></param> /// <param name="diagramPointEventArgs"></param> public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs) { // CHANGE THIS CODE FOR YOUR APPLICATION. // Get the target shape, if any. Null if the target is the diagram. IShape targetIShape = targetElement.CreateIShape(); // Do something... } /// <summary> /// Called repeatedly when the user drags from anywhere on the screen. /// Return value should indicate whether a drop here is allowed. /// </summary> /// <param name="targetMergeElement">References the element to be dropped on.</param> /// <param name="diagramDragEventArgs">References the element to be dropped.</param> /// <returns></returns> public bool CanDragDrop(ShapeElement targetMergeElement, DiagramDragEventArgs diagramDragEventArgs) { // CHANGE THIS CODE FOR YOUR APPLICATION. // Get the target element, if any. Null if the target is the diagram. IShape targetIShape = targetMergeElement.CreateIShape(); // This example allows drag of any UML elements. return GetModelElementsFromDragEvent(diagramDragEventArgs).Count() > 0; } /// <summary> /// Execute the action to be performed on the drop. /// </summary> /// <param name="targetDropElement"></param> /// <param name="diagramDragEventArgs"></param> public void OnDragDrop(ShapeElement targetDropElement, DiagramDragEventArgs diagramDragEventArgs) { // CHANGE THIS CODE FOR YOUR APPLICATION. } /// <summary> /// Retrieves UML IElements from drag arguments. /// Works for drags from UML diagrams. /// </summary> private IEnumerable<IElement> GetModelElementsFromDragEvent (DiagramDragEventArgs dragEvent) { //ElementGroupPrototype is the container for //dragged and copied elements and toolbox items. ElementGroupPrototype prototype = dragEvent.Data. GetData(typeof(ElementGroupPrototype)) as ElementGroupPrototype; // Locate the originals in the implementation store. IElementDirectory implementationDirectory = dragEvent.DiagramClientView.Diagram.Store.ElementDirectory; return prototype.ProtoElements.Select( prototypeElement => { ModelElement element = implementationDirectory .FindElement(prototypeElement.ElementId); ShapeElement shapeElement = element as ShapeElement; if (shapeElement != null) { // Dragged from a diagram. return shapeElement.ModelElement as IElement; } else { // Dragged from UML Model Explorer. return element as IElement; } }); } } }
Weitere Informationen zum Füllen der Methoden finden Sie unter Implementieren des Gestenhandlers.
Sie müssen den Menübefehl einem VSIX-Projekt hinzufügen, das als Container für die Installation des Befehls fungiert.Gegebenenfalls können Sie in dasselbe VSIX auch weitere Komponenten einschließen.
So fügen Sie einem VSIX-Projekt einen separaten Gestenhandler hinzu
Sie benötigen diese Schritte nicht, wenn Sie den Gestenhandler mit seiner eigenen VSIX erstellt haben.
Erstellen Sie ein VSIX-Projekt, sofern die Projektmappe noch kein VSIX-Projekt enthält.
In Projektmappen-Explorer im Kontextmenü der Projektmappe, wählen Sie Hinzufügen, Neues Projekt aus.
Erweitern Sie unter Installierte VorlagenVisual C# oder Visual Basic, wählen Sie Erweiterungen aus.In der mittleren Spalte wählen Sie VSIX-Projekt aus.
Legen Sie das VSIX-Projekt als Startprojekt der Projektmappe fest.
- Wählen Sie im Projektmappen-Explorer, im Kontextmenü des VSIX-Projekts, Als Startprojekt festlegen aus.
In source.extension.vsixmanifest fügen Sie das Gestenhandler-Klassenbibliotheksprojekt als MEF-Komponente hinzu:
Klicken Sie auf der Registerkarte Metadaten legen Sie einen Namen für das VSIX fest.
Klicken Sie auf der Registerkarte Ziele installieren legen Sie Visual Studio Premium und Ultimate als die Ziele fest.
Klicken Sie auf der Registerkarte Objekte wählen Sie Neu und, Satz aus:
Typ = MEF-Komponente
Quelle = Ein Projekt in der aktuellen Projektmappe
Projekt = das Klassenbibliotheksprojekt
Ausführen des Gestenhandlers
Führen Sie den Gestenhandler zu Testzwecken im Debugmodus aus.
So testen Sie den Gestenhandler
Drücken Sie F5, oder klicken Sie im Menü Debuggen auf Debuggen starten.
Eine experimentelle Instanz von Visual Studio wird gestartet.
Problembehandlung: Wenn ein neuer Visual Studio nicht startet:
Wenn Sie mehr als ein Projekt haben, stellen Sie sicher, dass das VSIX-Projekt als Startprojekt der Projektmappe festgelegt wird.
Wählen Sie im Projektmappen-Explorer, im Kontextmenü des Starts oder nur des Projekts, Eigenschaften.im Projekteigenschaften-Editor Debuggen wählen Sie die Registerkarte aus.Stellen Sie sicher, dass die Zeichenfolge im Feld Externes Programm starten der vollständige Pfadname von Visual Studio ist. Dieser lautet in der Regel:
C:\Programme\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe
Öffnen oder erstellen Sie in der experimentellen Instanz von Visual Studio ein Modellierungsprojekt, und öffnen oder erstellen Sie ein Modellierungsdiagramm.Verwenden Sie ein Diagramm, das zu einem der Typen gehört, die in den Attributen der Gestenhandlerklasse aufgeführt sind.
Doppelklicken Sie auf eine beliebige Stelle im Diagramm.Der Doppelklickhandler sollte aufgerufen werden.
Ziehen Sie ein Element aus dem UML-Explorer auf das Diagramm.Der Ziehhandler sollte aufgerufen werden.
Problembehandlung: Wenn der Gestenhandler nicht ordnungsgemäß funktioniert, stellen Sie Folgendes sicher:
Das Gestenhandlerprojekt ist als MEF-Komponente auf der Registerkarte Objekte in source.extensions.manifest im VSIX-Projekt aufgeführt.
Die Parameter aller Import-Attribute und Export-Attribute sind gültig.
Die CanDragDrop-Methode gibt nicht false zurück.
Der verwendete Modelldiagrammtyp (UML-Klasse, Sequenz usw.) ist als eines der Gestenhandler-Klassenattribute [ClassDesignerExtension], [SequenceDesignerExtension] usw. aufgeführt.
Für diesen Typ des Zielelements und des abgelegten Elements ist noch keine integrierte Funktionalität definiert.
Implementieren des Gestenhandlers
Die Gestenhandlermethoden
Die Gestenhandlerklasse implementiert und exportiert IGestureExtension.Sie müssen die folgenden Methoden definieren:
bool CanDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent) |
Geben Sie true zurück, um für das Quellelement, auf das in dragEvent verwiesen wird, das Ablegen auf diesem Ziel zu ermöglichen. Diese Methode darf keine Änderungen am Modell vornehmen.Sie muss schnell ausgeführt werden, da damit der Pfeilzustand bestimmt wird, während der Benutzer die Maus bewegt. |
void OnDragDrop (ShapeElement target, DiagramDragEventArgs dragEvent) |
Aktualisieren Sie das Modell basierend auf dem Zielobjekt und auf dem Quellobjekt, auf das in dragEvent verwiesen wird. Wird aufgerufen, wenn der Benutzer die Maus nach dem Ziehvorgang loslässt. |
void OnDoubleClick (ShapeElement target, DiagramPointEventArgs pointEvent) |
target ist die Form, auf die der Benutzer doppelt geklickt hat. |
Sie können Handler schreiben, die nicht nur UML akzeptieren, sondern auch eine Vielzahl anderer Elemente, z. B. Dateien, Knoten in einer .NET-Klassenansicht, Architektur-Explorer-Knoten usw.Benutzer können diese Elemente in ein UML-Diagramm ziehen, wenn Sie eine OnDragDrop-Methode schreiben, die die serialisierte Form der Elemente decodieren kann.Die Decodierungsmethoden variieren von Elementtyp zu Elementtyp.
Die Parameter dieser Methoden lauten wie folgt:
ShapeElement target.Die Form oder das Diagramm, auf die bzw. das der Benutzer ein Element gezogen hat.
ShapeElement ist eine Klasse in der Implementierung, die den UML-Modellierungstools zugrunde liegt.Um das Risiko von Inkonsistenzen im UML-Modell und in den Diagrammen zu reduzieren, sollten die Methoden dieser Klasse nicht direkt verwendet werden.Umschließen Sie das Element stattdessen in einer IShape, und verwenden Sie dann die in Gewusst wie: Anzeigen eines Modells in Diagrammen beschriebenen Methoden.
Abrufen einer IShape:
IShape targetIShape = target.CreateIShape(target);
Abrufen des Modellelements, das das Ziel des Drag & Drop-Vorgangs ist:
IElement target = targetIShape.Element;
Sie können das Element in einen spezifischeren Typ von Element umwandeln.
Abrufen des UML-Modellspeichers, der das UML-Modell enthält:
IModelStore modelStore = targetIShape.Element.GetModelStore();
So erhalten Sie Zugriff auf den Host und Dienstanbieter
target.Store.GetService(typeof(EnvDTE.DTE)) as EnvDTE.DTE
DiagramDragEventArgs eventArgs.Dieser Parameter enthält die serialisierte Form des Quellobjekts eines Ziehvorgangs:
System.Windows.Forms.IDataObject data = eventArgs.Data;
Sie können viele unterschiedliche Elemente aus verschiedenen Teilen von Visual Studio oder vom Windows-Desktop in ein Diagramm ziehen.Unterschiedliche Elementtypen werden in IDataObject unterschiedlich codiert.Informationen zum Extrahieren der Elemente finden Sie in der Dokumentation für den jeweiligen Objekttyp.
Wenn das Quellobjekt ein aus dem UML-Modell-Explorer oder einem anderen UML-Diagramm gezogenes UML-Element ist, können Sie die entsprechenden Informationen unter Gewusst wie: Abrufen von UML-Modellelementen aus IDataObject nachlesen.
Schreiben des Methodencodes
Weitere Informationen über das Schreiben des Codes zum Lesen und Aktualisieren des Modells finden Sie unter Programmieren mit der UML-API.
Informationen zum Zugreifen auf Modellinformationen in einem Ziehvorgang finden Sie unter Gewusst wie: Abrufen von UML-Modellelementen aus IDataObject.
Wenn Sie mit einem Sequenzdiagramm arbeiten, finden Sie unter Gewusst wie: Bearbeiten von Sequenzdiagrammen mit der UML-API weitere Informationen.
Zusätzlich zu den Parametern der Methoden können Sie auch eine importierte Eigenschaft in der Klasse deklarieren, die Zugriff auf das aktuelle Diagramm und Modell bietet.
[Import] public IDiagramContext DiagramContext { get; set; }
Die IDiagramContext-Deklaration ermöglicht es Ihnen, in den Methoden Code zu schreiben, der auf das Diagramm, die aktuelle Auswahl und das Modell zugreift:
IDiagram diagram = this.DiagramContext.CurrentDiagram;
foreach (IShape<IElement> shape in diagram.GetSelectedShapes<IElement>)
{ IElement element = shape.Element; ... }
IModelStore modelStore = diagram.ModelStore;
IModel model = modelStore.Root;
foreach (IDiagram diagram in modelStore.Diagrams) {...}
foreach (IElement element in modelStore.AllInstances<IUseCase>) {...}
Weitere Informationen finden Sie unter Gewusst wie: Navigieren im UML-Modell.
Installieren und Deinstallieren einer Erweiterung
Sie können eine Visual Studio-Erweiterung sowohl auf Ihrem eigenen Computer als auch auf anderen Computern installieren.
So installieren Sie eine Erweiterung
Suchen Sie auf dem Computer nach der .vsix-Datei, die vom VSIX-Projekt erstellt wurde.
In Projektmappen-Explorer im Kontextmenü des VSIX-Projekts, wählen Sie Ordner in Windows Explorer öffnen aus.
Suchen Sie nach der Datei bin\*\IhrProjekt.vsix.
Kopieren Sie die .vsix-Datei auf den Zielcomputer, auf dem Sie die Erweiterung installieren möchten.Dies kann Ihr eigener Computer oder ein anderer Computer sein.
Der Zielcomputer muss über eine der Editionen von Visual Studio verfügen, die Sie in source.extension.vsixmanifest angegeben haben.
Klicken Sie auf dem Zielcomputer Sie die .vsix Datei.
Installer für Visual Studio-Erweiterungen wird geöffnet, und die Erweiterung wird installiert.
Starten Sie Visual Studio, bzw. starten Sie die Anwendung neu.
So deinstallieren Sie eine Erweiterung
Klicken Sie im Menü Tools wählen Sie Erweiterungs-Manager aus.
Erweitern Sie Installierte Erweiterungen.
Wählen Sie die Erweiterung aus, und wählen Sie dann Deinstallieren aus.
In seltenen Fällen kann es vorkommen, dass eine fehlerhafte Erweiterung nicht geladen und ein Bericht im Fehlerfenster erstellt wird, aber im Erweiterungs-Manager keine Informationen angezeigt werden.Sie haben die Möglichkeit, die Erweiterung zu entfernen, indem Sie die Datei aus dem folgenden Ordner löschen:
%LocalAppData%\Local\Microsoft\VisualStudio\11.0\Extensions
Beispiel
Im folgenden Beispiel wird gezeigt, wie basierend auf den Teilen und Anschlüssen einer aus einem Komponentendiagramm gezogenen Komponente Lebenslinien in einem Sequenzdiagramm erstellt werden.
Drücken Sie zum Testen F5.Eine experimentelle Instanz von Visual Studio wird geöffnet.Öffnen Sie in dieser Instanz ein UML-Modell, und erstellen Sie in einem Komponentendiagramm eine Komponente.Fügen Sie dieser Komponente einige Schnittstellen und interne Komponententeile hinzu.Wählen Sie die Schnittstellen und die Teile aus.Ziehen Sie anschließend die Schnittstellen und die Teile auf ein Sequenzdiagramm.(Ziehen Sie aus dem Komponentendiagramm hinauf bis zur Registerkarte für das Sequenzdiagramm und anschließend hinunter in das Sequenzdiagramm.) Für jede Schnittstelle und jedes Teil wird eine Lebenslinie angezeigt.
Weitere Informationen zum Binden von Interaktionen an Sequenzdiagramme finden Sie unter Gewusst wie: Bearbeiten von Sequenzdiagrammen mit der UML-API.
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using Microsoft.VisualStudio.Modeling.Diagrams.ExtensionEnablement;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.Uml.AuxiliaryConstructs;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Uml.Interactions;
using Microsoft.VisualStudio.Uml.CompositeStructures;
using Microsoft.VisualStudio.Uml.Components;
/// <summary>
/// Creates lifelines from component ports and parts.
/// </summary>
[Export(typeof(IGestureExtension))]
[SequenceDesignerExtension]
public class CreateLifelinesFromComponentParts : IGestureExtension
{
[Import]
public IDiagramContext Context { get; set; }
/// <summary>
/// Called by the modeling framework when
/// the user drops something on a target.
/// </summary>
/// <param name="target">The target shape or diagram </param>
/// <param name="dragEvent">The item being dragged</param>
public void OnDragDrop(ShapeElement target,
DiagramDragEventArgs dragEvent)
{
ISequenceDiagram diagram = Context.CurrentDiagram
as ISequenceDiagram;
IInteraction interaction = diagram.Interaction;
if (interaction == null)
{
// Sequence diagram is empty: create an interaction.
interaction = diagram.ModelStore.Root.CreateInteraction();
interaction.Name = Context.CurrentDiagram.Name;
diagram.Bind(interaction);
}
foreach (IConnectableElement connectable in
GetConnectablesFromDrag(dragEvent))
{
ILifeline lifeline = interaction.CreateLifeline();
lifeline.Represents = connectable;
lifeline.Name = connectable.Name;
}
}
/// <summary>
/// Called by the modeling framework to determine whether
/// the user can drop something on a target.
/// Must not change anything.
/// </summary>
/// <param name="target">The target shape or diagram</param>
/// <param name="dragEvent">The item being dragged</param>
/// <returns>true if this item can be dropped on this target</returns>
public bool CanDragDrop(ShapeElement target,
DiagramDragEventArgs dragEvent)
{
IEnumerable<IConnectableElement> connectables = GetConnectablesFromDrag(dragEvent);
return connectables.Count() > 0;
}
///<summary>
/// Get dragged parts and ports of an IComponent.
///</summary>
private IEnumerable<IConnectableElement>
GetConnectablesFromDrag(DiagramDragEventArgs dragEvent)
{
foreach (IElement element in
GetModelElementsFromDragEvent(dragEvent))
{
IConnectableElement part = element as IConnectableElement;
if (part != null)
{
yield return part;
}
}
}
/// <summary>
/// Retrieves UML IElements from drag arguments.
/// Works for drags from UML diagrams.
/// </summary>
private IEnumerable<IElement> GetModelElementsFromDragEvent
(DiagramDragEventArgs dragEvent)
{
//ElementGroupPrototype is the container for
//dragged and copied elements and toolbox items.
ElementGroupPrototype prototype =
dragEvent.Data.
GetData(typeof(ElementGroupPrototype))
as ElementGroupPrototype;
// Locate the originals in the implementation store.
IElementDirectory implementationDirectory =
dragEvent.DiagramClientView.Diagram.Store.ElementDirectory;
return prototype.ProtoElements.Select(
prototypeElement =>
{
ModelElement element = implementationDirectory
.FindElement(prototypeElement.ElementId);
ShapeElement shapeElement = element as ShapeElement;
if (shapeElement != null)
{
// Dragged from a diagram.
return shapeElement.ModelElement as IElement;
}
else
{
// Dragged from UML Model Explorer.
return element as IElement;
}
});
}
public void OnDoubleClick(ShapeElement targetElement, DiagramPointEventArgs diagramPointEventArgs)
{
}
}
Der Code von GetModelElementsFromDragEvent() wird in Gewusst wie: Abrufen von UML-Modellelementen aus IDataObject beschrieben.
Siehe auch
Konzepte
Gewusst wie: Definieren und Installieren einer Modellierungserweiterung
Erweitern von UML-Modellen und Diagrammen
Gewusst wie: Definieren eines Menübefehls in einem Modellierungsdiagramm
Gewusst wie: Definieren von Validierungseinschränkungen für UML-Modelle