Freigeben über


Grundlegendes zum DSL-Code

Eine DSL-Projektmappe (Domain-Specific Language, domänenspezifische Sprache) generiert eine API, die Sie zum Lesen und Aktualisieren von Instanzen der DSL in Visual Studio verwenden können. Diese API wird im Code definiert, der aus der DSL-Definition generiert wird. In diesem Thema wird die generierte API beschrieben.

Beispielprojektmappe: Komponentendiagramme

Um die Projektmappe zu erstellen, die in den meisten Beispielen in diesem Thema als Quelle verwendet wird, erstellen Sie eine DSL aus der Projektmappenvorlage Komponentenmodelle. Dies ist eine der Standardvorlagen, die angezeigt wird, wenn Sie eine neue DSL-Projektmappe erstellen.

Hinweis

Die DSL-Vorlage für Komponentendiagramme hat keinen Bezug zu den UML-Komponentendiagrammen, die Sie über das Menü "Architektur" in Visual Studio Ultimate erstellen können.Erweitern Sie im Dialogfeld Neues Projekt den Knoten Andere Projekttypen\Erweiterungen, und klicken Sie dann auf Domänenspezifischer Sprach-Designer.

Drücken Sie F5, und experimentieren Sie, wenn Sie mit dieser Projektmappenvorlage nicht vertraut sind. Achten Sie insbesondere darauf, dass Sie Ports erstellen, indem Sie ein Port-Tool auf eine Komponente ziehen, und dass Sie Verbindungen mit Ports herstellen können.

Komponenten und verbundene Ports

Struktur der DSL-Projektmappe

Das Dsl-Projekt definiert die API für Ihre DSL. Das DslPackage-Projekt definiert deren Integration in Visual Studio. Sie können auch eigene Projekte hinzufügen, die durch das Modell generierten Code enthalten können.

Codeverzeichnisse

Der Großteil des Codes in diesen Projekten wird über Dsl\DslDefinition.dsl generiert. Der generierte Code befindet sich im Ordner Generated Code. Sie können eine generierte Datei anzeigen, indem Sie auf [+] neben der .tt-Generierungsdatei klicken.

Es empfiehlt sich, den generierten Code zu untersuchen, damit Sie die DSL besser verstehen. Erweitern Sie zum Anzeigen der generierten Dateien die TT-Dateien im Projektmappen-Explorer.

Die TT-Dateien enthalten sehr wenig Generierungscode. Stattdessen verwenden sie <#include>-Direktiven, um freigegebene Vorlagendateien einzubinden. Sie finden die freigegebenen Dateien unter \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\DSL SDK\DSL Designer\11.0\TextTemplates

Wenn Sie der DSL-Projektmappe eigenen Programmcode hinzufügen, nutzen Sie dafür eine separate Datei außerhalb des Ordners für generierten Code. Sie könnten einen Ordner Custom Code erstellen. (Wenn Sie eine neue Codedatei einem benutzerdefinierten Ordner hinzufügen, müssen Sie den Namespace im anfänglichen Codeskelett korrigieren.)

Wir raten dringend davon ab, den generierten Code direkt zu bearbeiten, da Ihre Änderungen verloren gehen, wenn Sie die Projektmappe neu erstellen. Passen Sie stattdessen Ihre DSL an:

  • Passen Sie die vielen Parameter in der DSL-Definition an.

  • Schreiben Sie partielle Klassen in separaten Codedateien, um Methoden zu überschreiben, die in den generierten Klassen definiert sind oder von ihnen geerbt werden. In einigen Fällen müssen Sie die Option Generiert doppelte Ableitungen einer Klasse in der DSL-Definition festlegen, damit Sie eine generierte Methode überschreiben können.

  • Legen Sie Optionen in der DSL-Definition fest, durch die der generierte Code "Hooks" für Ihren eigenen Code bereitstellt.

    Wenn Sie beispielsweise die Option Hat benutzerdefinierten Konstruktor einer Domänenklasse festlegen und dann die Projektmappe erstellen, werden Fehlermeldungen angezeigt. Wenn Sie auf eine dieser Fehlermeldungen doppelklicken, sehen Sie Kommentare im generierten Code, die erläutern, was der benutzerdefinierte Code enthalten sollte.

  • Schreiben Sie eigene Textvorlagen, um Code speziell für Ihre Anwendung zu erstellen. Mit Includedateien können Sie Teile der Vorlagen freigeben, die in vielen Projekten gleich sind. Darüber hinaus können Sie Visual Studio-Projektvorlagen erstellen, die mit Ihrer eigenen Dateistruktur initialisiert werden.

Generierte Dateien in "Dsl"

Die folgenden generierten Dateien werden im Dsl-Projekt angezeigt.

Dateiname

Beschreibung

IhrDslSchema.xsd

Das Schema für Dateien, die Instanzen Ihrer DSL enthalten. Die Datei wird in das Kompilierungsverzeichnis (bin) kopiert. Wenn Sie Ihre DSL installieren, können Sie diese Datei nach \Program Files\Microsoft Visual Studio 11.0\Xml\Schemas kopieren, sodass Modelldateien überprüft werden können. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.

Wenn Sie die Serialisierung durch Festlegen von Optionen im DSL-Explorer anpassen, ändert sich das Schema entsprechend. Wenn Sie jedoch eigenen Serialisierungscode schreiben, bildet diese Datei das eigentliche Schema möglicherweise nicht mehr ab. Weitere Informationen finden Sie unter Customizing File Storage and XML Serialization.

ConnectionBuilders.cs

Ein Verbindungs-Generator ist eine Klasse, die Beziehungen erstellt. Es ist der Code für ein Verbindungstool. Diese Datei enthält ein Paar von Klassen für jedes Verbindungstool. Die Namen werden von den Namen der Domänenbeziehung und des Verbindungstools abgeleitet: BeziehungBuilder und KonnektortoolConnectAction.

(Im Beispiel der Komponentenprojektmappe trägt einer der Verbindungs-Generatoren den Namen "ConnectionBuilder". Dies ist ein Zufall, da die Domänenbeziehung "Connection" genannt wurde.)

Die Beziehung wird in der Methode BeziehungBuilder.Connect() erstellt. Die Standardversion überprüft, ob die Quell- und Zielmodellelemente akzeptiert werden können und instanziiert dann die Beziehung. Beispiel:

CommentReferencesSubject(sourceAccepted, targetAccepted);

Jede Generator-Klasse wird über einen Knoten im Abschnitt Verbindungs-Generatoren im DSL-Explorer generiert. Eine Connect-Methode kann Beziehungen zwischen einem oder mehreren Paaren von Domänenklassen erstellen. Jedes Paar wird durch eine Direktive für Linkverbindungen definiert, die Sie im DSL-Explorer unter dem Generator-Knoten finden.

Sie könnten beispielsweise einem Verbindungs-Generator Direktiven für Linkverbindungen für jeden der drei Typen von Beziehungen in der Beispiel-DSL hinzufügen. Auf diese Weise erhält der Benutzer ein einziges Verbindungstool. Der Typ der instanziierten Beziehung hängt von den Typen der Quell- und Zielelemente ab, die vom Benutzer ausgewählt werden. Klicken Sie zum Hinzufügen von Direktiven für Linkverbindungen mit der rechten Maustaste auf einen Generator im DSL-Explorer.

Wählen Sie zum Schreiben von benutzerdefiniertem Code, der bei der Erstellung eines bestimmten Typs von Domänenbeziehung ausgeführt wird, unter dem Generator-Knoten die entsprechende Direktive für Linkverbindungen aus. Legen Sie im Eigenschaftenfenster Verwendet benutzerdefiniertes Verbinden fest. Erstellen Sie die Projektmappe, und stellen Sie dann den Code bereit, um die entstandenen Fehler zu korrigieren.

Um benutzerdefinierten Code zu schreiben, der immer ausgeführt wird, wenn der Benutzer dieses Verbindungstool verwendet, legen Sie die Eigenschaft Ist benutzerdefiniert des Verbindungs-Generators fest. Sie können Code bereitstellen, der bestimmt, ob ein Element zulässig ist, ob eine bestimmte Kombination aus Quelle und Ziel zulässig ist und welche Aktualisierungen am Modell vorgenommen werden sollen, wenn eine Verbindung hergestellt wird. Sie könnten eine Verbindung beispielsweise nur zulassen, wenn damit keine Schleife im Diagramm erstellt wird. Statt eines einzelnen Beziehungslinks könnten Sie eine komplexeres Muster mehrerer miteinander verknüpfter Elemente zwischen Quelle und Ziel instanziieren.

Connectors.cs

Enthält die Klassen für die Konnektoren, bei denen es sich um die Diagrammelemente handelt, die üblicherweise Verweisbeziehungen darstellen. Jede Klasse wird aus einem Konnektor in der DSL-Definition generiert. Jede Konnektorklasse wird von BinaryLinkShape abgeleitet.

Damit die Farbe und andere Stilmerkmale zur Laufzeit variabel sind, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Verfügbare hinzufügen.

Informationen dazu, wie weitere Stilmerkmale zur Laufzeit variabel gemacht werden, finden Sie in den Beispielen TextField und ShapeElement.

Diagram.cs

Enthält die Klasse, die das Diagramm definiert. Sie wird von Diagram abgeleitet.

Damit die Farbe und andere Stilmerkmale zur Laufzeit variabel sind, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Verfügbare hinzufügen.

Darüber hinaus enthält die Datei die Regel FixupDiagram, die angewendet wird, wenn dem Modell ein neues Element hinzugefügt wird. Die Regel fügt eine neue Form hinzu und verknüpft die Form mit dem Modellelement.

DirectiveProcessor.cs

Mit diesem Direktivenprozessor können Ihre Benutzer Textvorlagen schreiben, die eine Instanz Ihrer DSL lesen. Der Direktivenprozessor lädt die Assemblys (DLLs) für Ihre DSL und fügt effektiv using-Anweisungen für Ihren Namespace ein. So kann der Code in den Textvorlagen die Klassen und Beziehungen verwenden, die Sie in Ihrer DSL definiert haben.

Weitere Informationen finden Sie unter Generating Code from a Domain-Specific Language und Erstellen von benutzerdefinierten T4-Direktivenprozessoren für Textvorlagen.

DomainClasses.cs

Implementierungen der Domänenklassen, die Sie definiert haben, einschließlich der abstrakten Klassen und der Modellstammklasse. Sie werden von ModelElement abgeleitet.

Jede Domänenklasse enthält Folgendes:

  • Eine Eigenschaftendefinition und eine geschachtelte Handlerklasse für jede Domäneneigenschaft. Sie können OnValueChanging() und OnValueChanged() überschreiben. Weitere Informationen finden Sie unter Handler für Wertänderungen von Domäneneigenschaften.

    In der Beispiel-DSL enthält die Comment-Klasse eine Text-Eigenschaft und eine TextPropertyHandler-Handlerklasse.

  • Accessoreigenschaften für die Beziehungen mit Beteiligung dieser Domänenklasse. (Es gibt keine geschachtelte Klasse für Rolleneigenschaften.)

    In der Beispiel-DSL weist die Comment-Klasse Accessoren auf, die über die Einbettungsbeziehung ComponentModelHasComments auf das übergeordnete Modell zugreifen.

  • Konstruktoren. Wenn Sie diese überschreiben möchten, legen Sie Hat benutzerdefinierten Konstruktor für die Domänenklasse fest.

  • EGP-Handlermethoden (Elementgruppenprototyp). Diese sind erforderlich, wenn der Benutzer ein anderes Element in Instanzen dieser Klasse zusammenführen (hinzufügen) kann. Üblicherweise führt der Benutzer dazu einen Ziehvorgang von einem Elementtool oder einer anderen Form oder einen Einfügevorgang aus.

    In der Beispiel-DSL kann ein Eingangsport oder ein Ausgangsport in einer Komponente zusammengeführt werden. Außerdem können Komponenten und Kommentare im Modell zusammengeführt werden.

    Die EGP-Handlermethoden in der Komponentenklasse lassen es zu, dass eine Komponente Ports akzeptiert, aber keine Kommentare. Der EGP-Handler in der Stammmodellklasse akzeptiert Kommentare und Komponenten, aber keine Ports.

DomainModel.cs

Die Klasse, die das Domänenmodell darstellt. Sie wird von DomainModel abgeleitet.

Hinweis

Sie ist nicht mit der Stammklasse des Modells identisch.

Mit Kopier- und Löschabschlüssen wird definiert, welche anderen Elemente aufgenommen werden sollen, wenn ein Element kopiert oder gelöscht wird. Sie können dieses Verhalten steuern, indem Sie die Eigenschaften Überträgt Kopie und Überträgt Löschung der Rollen auf beiden Seiten jeder Beziehung festlegen. Wenn die Werte dynamisch ermittelt werden sollen, können Sie Code schreiben, um die Methoden der Abschlussklassen zu überschreiben. Weitere Informationen finden Sie unter How to: Program Copy and Paste Behavior - redirect.

DomainModelResx.resx

Enthält Zeichenfolgen wie die Beschreibungen von Domänenklassen und -eigenschaften, Eigenschaftennamen, Toolboxbezeichnungen, Standardfehlermeldungen und andere Zeichenfolgen, die dem Benutzer angezeigt werden können. Die Datei könnte auch Toolsymbole und Bilder für Bildformen enthalten.

Diese Datei ist an die erstellte Assembly gebunden und enthält die Standardwerte für diese Ressourcen. Sie können Ihre DSL lokalisieren, indem Sie eine Satellitenassembly erstellen, die eine lokalisierte Version der Ressourcen enthält. Diese Version wird verwendet, wenn die DSL in einer Kultur erstellt wird, die mit den lokalisierten Ressourcen übereinstimmt. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.

DomainRelationships.cs

Jeder Link zwischen zwei Elementen in einem Modell wird durch eine Instanz einer Domänenbeziehungsklasse dargestellt. Alle Beziehungsklassen werden von ElementLink abgeleitet, der wiederum von ModelElement abgeleitet wird. Da es sich um ein ModelElement handelt, kann eine Instanz einer Beziehung Eigenschaften aufweisen und die Quelle oder das Ziel einer Beziehung sein.

HelpKeywordHelper.cs

Stellt Funktionen bereit, die verwendet werden, wenn der Benutzer F1 drückt.

MultiplicityValidation.cs

In Beziehungsrollen, in denen Sie die Multiplizität 1..1 oder 1..* angegeben haben, sollte der Benutzer informiert werden, dass mindestens eine Instanz der Beziehung erforderlich ist. Diese Datei enthält Validierungseinschränkungen, mit denen diese Warnungen implementiert werden. Der Link 1..1 zu einem übergeordneten Einbettungselement wird nicht überprüft.

Damit diese Einschränkungen ausgeführt werden, müssen Sie eine der Optionen Verwendet... im Knoten Editor\Validierung im DSL-Explorer festlegen. Weitere Informationen finden Sie unter Validierung in einer domänenspezifischen Sprache.

PropertiesGrid.cs

Diese Datei enthält nur Code, wenn Sie einer Domäneneigenschaft einen benutzerdefinierten Typdeskriptor angefügt haben. Weitere Informationen finden Sie unter Customizing the Properties Window.

SerializationHelper.cs

  • Eine Validierungsmethode, mit der sichergestellt wird, dass ein Moniker nicht auf zwei Elemente verweist. Weitere Informationen finden Sie unter Customizing File Storage and XML Serialization.

  • SerializationHelper-Klasse, die Funktionen bereitstellt, die von Serialisierungsklassen gemeinsam verwendet werden.

Serializer.cs

Eine Serialisierungsklasse für alle Domänenklassen, Beziehungen, Formen, Konnektoren, Diagramme und Modelle.

Viele der Funktionen dieser Klassen können durch die Einstellungen im DSL-Explorer unter XML-Serialisierungsverhalten gesteuert werden.

Shapes.cs

Eine Klasse für jede Formklasse in der DSL-Definition. Formen werden von NodeShape abgeleitet. Weitere Informationen finden Sie unter Customizing File Storage and XML Serialization.

Sie können die generierten Methoden mit eigenen Methoden in einer partiellen Klasse überschreiben, indem Sie Generiert doppelte Ableitungen für den Konnektor in der DSL-Definition festlegen. Um einen Konstruktor durch eigenen Code zu ersetzen, legen Sie Hat benutzerdefinierten Konstruktor fest.

Damit die Farbe und andere Stilmerkmale zur Laufzeit variabel sind, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Verfügbare hinzufügen.

Informationen dazu, wie weitere Stilmerkmale zur Laufzeit variabel gemacht werden, finden Sie in den Beispielen TextField und ShapeElement.

ToolboxHelper.cs

Richtet die Toolbox ein, indem Elementgruppenprototypen in den Elementtools installiert werden. Kopien dieser Prototypen werden mit den Zielelementen zusammengeführt, wenn der Benutzer das Tool ausführt.

Sie könnten CreateElementPrototype() überschreiben, um ein Toolboxelement zu definieren, mit dem eine Gruppe aus mehreren Objekten erstellt wird. Sie könnten z. B. ein Element definieren, das Objekte mit Unterkomponenten darstellt. Setzen Sie nach den Codeänderungen die experimentelle Instanz von Visual Studio zurück, um den Toolboxcache zu leeren.

Generierte Dateien im DslPackage-Projekt

"DslPackage" verbindet das DSL-Modell mit der Visual Studio-Shell und verwaltet Fenster-, Toolbox- und Menübefehle. Die meisten der Klassen werden doppelt abgeleitet, sodass Sie deren Methoden überschreiben können.

Dateiname

Beschreibung

CommandSet.cs

Die Kontextmenübefehle, die auf dem Diagramm angezeigt werden. Sie können diesen Satz anpassen oder erweitern. Diese Datei enthält den Code für die Befehle. Die Position der Befehle in Menüs wird durch die Datei "Commands.vsct" bestimmt. Weitere Informationen finden Sie unter Schreiben von Benutzerbefehlen und -aktionen.

Constants.cs

GUIDs.

DocData.cs

Mit IhrDslDocData wird das Laden und Speichern eines Modells in einer Datei verwaltet und die Speicherinstanz erstellt.

Wenn Sie Ihre DSL beispielsweise in einer Datenbank statt in einer Datei speichern möchten, können Sie die Methoden Load und Save überschreiben.

DocView.cs

Mit IhrDslDocView wird das Fenster verwaltet, in dem das Diagramm angezeigt wird. Sie könnten das Diagramm beispielsweise in eine Windows Form einbetten:

Fügen Sie dem DslPackage-Projekt eine Datei mit Benutzersteuerelementen hinzu. Fügen Sie ein Panel hinzu, in dem das Diagramm angezeigt werden kann. Fügen Sie Schaltflächen und andere Steuerelemente hinzu. Fügen Sie in der Codeansicht des Formulars den folgenden Code hinzu; passen Sie dabei die Namen an Ihre DSL an:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Shell;
namespace Company.EmbedInForm
{
  public partial class UserControl1 : UserControl
  {
    public UserControl1()
    {
      InitializeComponent();
    }
    
    private DiagramDocView docView;
    public UserControl1(DiagramDocView docView, Control content)
      : this()
    {
      this.docView = docView;
      panel1.Controls.Add(content);
    }
    private void button1_Click(object sender, EventArgs e)
    {
      ExampleModel modelRoot = this.docView.CurrentDiagram.ModelElement as ExampleModel;
      foreach (ExampleElement element in modelRoot.Elements)
      {
       listBox1.Items.Add(element.Name);
      }
    }
  }
  internal partial class EmbedInFormDocView
  {
    private ContainerControl container;
    /// <summary>
    /// Return a User Control instead of the DSL window. 
    /// The user control will contain the DSL window.
    /// </summary>
    public override System.Windows.Forms.IWin32Window Window
    {
      get
      {
        if (container == null)
        {
          // Put the normal DSL Window inside our control
          container = new UserControl1(this, (Control)base.Window);
        }
        return container;
      }
    }
  }
}

EditorFactory.cs

Instanziiert DocData und DocView. Damit wird eine Standardschnittstelle erfüllt, die von Visual Studio zum Öffnen eines Editors verwendet wird, wenn Ihr DSL-Paket startet. Auf die Datei wird im ProvideEditorFactory-Attribut in "Package.cs" verwiesen.

GeneratedVSCT.vsct

Bestimmt die Position der standardmäßigen Menübefehle in Menüs, beispielsweise das Diagrammkontextmenü, das Menü Bearbeiten usw. Der Code für die Befehle befindet sich in "CommandSet.cs". Sie können die Standardbefehle verschieben oder ändern, und Sie können eigene Befehle hinzufügen. Weitere Informationen finden Sie unter Schreiben von Benutzerbefehlen und -aktionen.

ModelExplorer.cs

Definiert den Modell-Explorer für Ihre DSL. Dies ist eine Strukturansicht des Modells, die dem Benutzer neben dem Diagramm angezeigt wird.

Sie könnten z. B. InsertTreeView() überschreiben, um die Reihenfolge zu ändern, in der Elemente im Modell-Explorer angezeigt werden.

Mit folgendem Code können Sie festlegen, dass die Auswahl im Modell-Explorer mit der Diagrammauswahl synchron bleibt:

protected override void OnSelectionChanged(global::System.EventArgs e)
{
base.OnSelectionChanged(e);
// get the selected element
DslModeling::ModelElement selectedElement = 
this.PrimarySelection as DslModeling::ModelElement;
// Select in the model explorer
SelectInModelExplorer<YOURLANGUAGEExplorerToolWindow>(selectedElement);
}
private void SelectInModelExplorer<T>(DslModeling::ModelElement modelElement)
where T : DslShell.ModelExplorerToolWindow
{
DslShell::ModelingPackage package = 
this.GetService(typeof(VSShell.Package)) as DslShell::ModelingPackage;
if (package != null)
{
// find the model explorer window
T explorerWindow = package.GetToolWindow(typeof(T), true) as T;
if (explorerWindow != null)
{
// get the tree container
DslShell.ModelExplorerTreeContainer treeContainer = 
explorerWindow.TreeContainer;
// find the tree node
DslShell.ExplorerTreeNode treeNode = 
treeContainer.FindNodeForElement(modelElement);
// select the node
explorerWindow.TreeContainer.ObjectModelBrowser.SelectedNode = treeNode;
}
}
}

ModelExplorerToolWindow.cs

Definiert das Fenster, in dem der Modell-Explorer angezeigt wird. Verarbeitet die Auswahl der Elemente im Explorer.

Package.cs

Diese Datei definiert, wie die DSL in Visual Studio integriert wird. Attribute in der Paketklasse registrieren die DSL als Handler für Dateien, die Ihre Dateierweiterung aufweisen, definieren die Toolbox und definieren, wie ein neues Fenster geöffnet wird. Die Initialize()-Methode wird einmal aufgerufen, wenn die erste DSL in eine Visual Studio-Instanz geladen wird.

Source.extension.vsixmanifest

Um diese Datei anzupassen, bearbeiten Sie die .tt-Datei.

Warnung

Wenn Sie die TT-Datei bearbeiten, damit sie Ressourcen wie Symbole oder Bilder enthält, stellen Sie sicher, dass die Ressourcen im VSIX-Build enthalten sind.Wählen Sie die Datei im Projektmappen-Explorer aus, und stellen Sie sicher, dass die Eigenschaft In VSIX aufnehmen auf True festgelegt ist.

Mit dieser Datei wird gesteuert, wie die DSL in eine Visual Studio-Integrationserweiterung (VSIX) verpackt wird. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.

Siehe auch

Konzepte

So definieren Sie eine domänenspezifische Sprache

Understanding Models, Classes and Relationships

Customizing and Extending a Domain-Specific Language

Weitere Ressourcen

Writing Code to Customise a Domain-Specific Language