Freigeben über


Grundlegendes zum DSL-Code

Eine Domain-Specific Language (DSL)-Lösung generiert eine API, mit der Sie Instanzen des DSL in Visual Studio lesen und aktualisieren können. Diese API wird im Code definiert, der aus der DSL-Definition generiert wird. In diesem Thema wird die generierte API beschrieben.

Die Beispiellösung: Komponentendiagramme

Um die Lösung zu erstellen, die die Quelle der meisten Beispiele in diesem Thema ist, erstellen Sie eine DSL aus der Lösungsvorlage "Komponentenmodelle ". Dies ist eine der Standardvorlagen, die angezeigt werden, wenn Sie eine neue DSL-Lösung erstellen.

Hinweis

Die Vorlage für die DSL "Komponentendiagramme" wird Domain-Specific Language Designer genannt.

Drücken Sie F5 , und experimentieren Sie, wenn Sie mit dieser Lösungsvorlage nicht vertraut sind. Beachten Sie insbesondere, dass Sie Ports erstellen, indem Sie ein Porttool auf eine Komponente ziehen, und dass Sie Ports verbinden können.

Komponenten und verbundene Ports

Die Struktur der DSL-Lösung

Das Dsl-Projekt definiert die API für Ihr DSL. Das DslPackage-Projekt definiert, wie es in Visual Studio integriert wird. Sie können auch eigene Projekte hinzufügen, die auch Code enthalten können, der aus dem Modell generiert wird.

Die Codeverzeichnisse

Der großteil des Codes in jedem dieser Projekte wird aus Dsl\DslDefinition.dsl generiert. Der generierte Code befindet sich im Ordner "Generierter Code ". Um eine generierte Datei anzuzeigen, klicken Sie neben der generierten TT-Datei auf [+].

Es wird empfohlen, den generierten Code zu prüfen, damit Sie das DSL verstehen können. Erweitern Sie die *.tt-Dateien im Projektmappen-Explorer, um die generierten Dateien anzuzeigen.

Die *.tt-Dateien enthalten sehr wenig generierenden Code. Stattdessen verwenden sie <#include>-Direktiven, um freigegebene Vorlagendateien einzubinden. Die freigegebenen Dateien finden Sie unter \Programme\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\DSL SDK\DSL Designer\11.0\TextTemplates

Wenn Sie der DSL-Lösung ihren eigenen Programmcode hinzufügen, fügen Sie ihn in einer separaten Datei außerhalb des Ordners "Generierter Code" hinzu. Möglicherweise möchten Sie einen Benutzerdefinierten Codeordner erstellen. (Wenn Sie einem benutzerdefinierten Ordner eine neue Codedatei hinzufügen, denken Sie daran, den Namespace im ursprünglichen Codeskelett zu korrigieren.)

Es wird dringend empfohlen, den generierten Code nicht direkt zu bearbeiten, da Ihre Bearbeitungen verloren gehen, wenn Sie die Lösung neu erstellen. Stattdessen um Ihr DSL anzupassen, folgen Sie diesen Schritten:

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

  • Schreiben Sie partielle Klassen in separaten Codedateien, um Methoden außer Kraft zu setzen, die in den generierten Klassen definiert oder geerbt werden. In einigen Fällen müssen Sie die Option " Doppelt abgeleitet generieren " einer Klasse in der DSL-Definition festlegen, um eine generierte Methode außer Kraft zu setzen.

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

    Wenn Sie beispielsweise die Option "Has Custom Constructor " einer Domänenklasse festlegen und dann die Lösung erstellen, werden Fehlermeldungen angezeigt. Wenn Sie auf eine dieser Fehlermeldungen doppelklicken, werden Kommentare im generierten Code angezeigt, die erläutern, was Ihr benutzerdefinierter Code bereitstellen soll.

  • Schreiben Sie Ihre eigenen Textvorlagen, um code speziell für Ihre Anwendung zu generieren. Sie können Dateien verwenden, um Teile der Vorlagen zu teilen, die für viele Projekte gemeinsam sind, und Sie können Visual Studio-Projektvorlagen erstellen, um Projekte einzurichten, die mit Ihrer eigenen Dateistruktur initialisiert werden.

Generierte Dateien in Dsl

Die folgenden generierten Dateien werden im Dsl-Projekt angezeigt.

YourDslSchema.xsd

Das Schema für Dateien, die Instanzen Ihres DSL enthalten. Diese Datei wird in das Kompilierungsverzeichnis (Bin) kopiert. Wenn Sie Ihr DSL installieren, können Sie diese Datei in \Programme\Microsoft Visual Studio 11.0\Xml\Schemas kopieren, damit Modelldateien überprüft werden können. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.

Wenn Sie die Serialisierung anpassen, indem Sie Optionen im DSL-Explorer festlegen, ändert sich das Schema entsprechend. Wenn Sie jedoch ihren eigenen Serialisierungscode schreiben, stellt diese Datei möglicherweise nicht mehr das tatsächliche Schema dar. Weitere Informationen finden Sie unter Anpassen der Dateispeicher- und XML-Serialisierung.

ConnectionBuilders.cs

Ein Verbindungs-Generator ist eine Klasse, die Beziehungen erstellt. Es ist der Code hinter einem Verbindungstool. Diese Datei enthält ein Klassenpaar für jedes Verbindungstool. Ihre Namen werden von den Namen der Domänenbeziehung und des Verbindungstools abgeleitet: Beziehungs-Generatorund ConnectorToolConnectAction.

(Im Beispiel für die Komponentenlösung wird einer der Verbindungs-Generatoren als ConnectionBuilder bezeichnet. Dies ist ein Zufall, da die Domänenbeziehung "Connection" heißt.)

Die Beziehung wird in der Relationship-MethodeBuilder.Connect() erstellt. Die Standardversion überprüft, ob die Quell- und Zielmodellelemente akzeptabel sind, und instanziiert dann die Beziehung. Beispiel:

CommentReferencesSubject(sourceAccepted, targetAccepted);

Jede Generatorklasse wird aus einem Knoten im Abschnitt "Verbindungs-Generatoren" im DSL-Explorer generiert. Eine Connect Methode kann Beziehungen zwischen einem oder mehreren Domänenklassenpaaren erstellen. Jedes Paar wird durch eine Link Connect-Direktive definiert, die Sie im DSL Explorer unter dem Generatorknoten finden können.

Sie könnten zum Beispiel einem Verbindungsbuilder Link-Connect-Direktiven für jeden der drei Beziehungstypen im Beispiel-DSL hinzufügen. Dies würde dem Benutzer ein einzelnes Verbindungstool bereitstellen. Der Typ der instanziierten Beziehung hängt von den Typen der vom Benutzer ausgewählten Quell- und Zielelemente ab. Klicken Sie zum Hinzufügen von Link Connect-Direktiven mit der rechten Maustaste auf einen Generator im DSL-Explorer.

Wenn Sie benutzerdefinierten Code schreiben möchten, der ausgeführt wird, wenn ein bestimmter Typ von Domänenbeziehung erstellt wird, wählen Sie die entsprechende Link Connect-Direktive unter dem Generatorknoten aus. Legen Sie im Eigenschaftenfenster 'Verwendet Benutzerdefinierte Verbindung' fest. Erstellen Sie die Lösung neu, und geben Sie dann Code an, um die resultierenden Fehler zu beheben.

Wenn Sie benutzerdefinierten Code schreiben möchten, der immer dann ausgeführt wird, wenn der Benutzer dieses Verbindungstool verwendet, legen Sie die Is Custom-Eigenschaft des Verbindungs-Generators fest. Sie können Code angeben, der entscheidet, ob ein Quellelement zulässig ist, ob eine bestimmte Kombination aus Quelle und Ziel zulässig ist und welche Aktualisierungen an dem Modell vorgenommen werden sollen, wenn eine Verbindung hergestellt wird. Beispielsweise können Sie eine Verbindung nur zulassen, wenn sie keine Schleife im Diagramm erstellen würde. Statt einer einzelnen Beziehungsverknüpfung können Sie ein komplexeres Muster mehrerer interbezogener Elemente zwischen der Quelle und dem Ziel instanziieren.

Connectors.cs

Enthält die Klassen für die Verbinder, bei denen es sich um die Diagrammelemente handelt, die in der Regel Referenzbeziehungen darstellen. Jede Klasse wird aus einem Connector in der DSL-Definition generiert. Jede Anschlussklasse ist von BinaryLinkShape abgeleitet

Um die Farbe und einige andere Stilmerkmale zur Laufzeit variabel zu gestalten, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Belichtung hinzufügen.

Zum Variabelmachen zusätzlicher Formatvorlagenfunktionen zur Laufzeit siehe beispielsweise TextField und ShapeElement.

Diagram.cs

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

Um die Farbe und einige andere Stilmerkmale zur Laufzeit variabel zu gestalten, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Belichtung hinzufügen.

Darüber hinaus enthält diese Datei die FixupDiagram Regel, die antwortet, wenn dem Modell ein neues Element hinzugefügt wird. Die Regel fügt ein neues Shape hinzu und verknüpft das Shape mit dem Modellelement.

DirectiveProcessor.cs

Dieser Direktivenprozessor hilft Ihren Benutzern, Textvorlagen zu schreiben, die eine Instanz Ihres DSL lesen. Der Direktivenprozessor lädt die Assemblies (DLLs) für Ihr DSL und fügt tatsächlich using Befehle für Ihren Namespace ein. Dadurch kann der Code in den Textvorlagen die Klassen und Beziehungen verwenden, die Sie in Ihrem DSL definiert haben.

Weitere Informationen finden Sie unter Generieren von Code aus einer Domain-Specific Sprache und Erstellen von benutzerdefinierten T4-Textvorlagen-Direktivenprozessoren.

DomainClasses.cs

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

Jede Domänenklasse enthält:

  • Eine Eigenschaftsdefinition und eine geschachtelte Handlerklasse für jede Domäneneigenschaft. Sie können OnValueChanging() und OnValueChanged() überschreiben. Weitere Informationen finden Sie unter Domain Property Value Change-Handler.

    Im Beispiel DSL enthält die Comment Klasse eine Eigenschaft Text und eine Handlerklasse TextPropertyHandler.

  • Accessor-Eigenschaften für die Beziehungen, an denen diese Domänenklasse teilnimmt. (Es gibt keine geschachtelte Klasse für Rolleneigenschaften.)

    Im Beispiel DSL verfügt die Comment Klasse über Accessoren, die über die Einbettungsbeziehung ComponentModelHasCommentsauf das übergeordnete Modell zugreifen.

  • Erbauer. Wenn Sie diese außer Kraft setzen möchten, legen Sie has Custom Constructor für die Domänenklasse fest.

  • Handlermethoden für Elementgruppenprototypen (EGP). Diese sind erforderlich, wenn der Benutzer ein weiteres Element in Instanzen dieser Klasse zusammenführen (hinzufügen kann). Normalerweise führt der Benutzer dies durch Ziehen aus einem Elementtool oder einem anderen Shape oder durch Einfügen aus.

    Im Beispiel DSL kann ein Input Port oder Output Port mit einer Komponente zusammengeführt werden. Außerdem können Komponenten und Kommentare mit dem Modell zusammengeführt werden. Das

    Mit den EGP-Handlermethoden in der Component-Klasse kann eine Komponente Ports akzeptieren, jedoch keine Kommentare. Der EGP-Handler in der Stammmodellklasse akzeptiert Kommentare und Komponenten, jedoch keine Ports.

    DomainModel.cs

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

Hinweis

Dies ist nicht mit der Stammklasse des Modells identisch.

Kopieren und Löschen von Schließungen definieren, welche anderen Elemente einbezogen werden sollen, wenn ein Element kopiert oder gelöscht wird. Sie können dieses Verhalten steuern, indem Sie die Eigenschaften " Kopieren verteilen" und " Löschweitergabe" der Rollen auf jeder Seite jeder Beziehung festlegen. Wenn die Werte dynamisch bestimmt werden sollen, können Sie Code schreiben, um die Methoden der Schließen-Klassen außer Kraft zu setzen.

DomainModelResx.resx

Dies enthält Zeichenfolgen wie die Beschreibungen von Domänenklassen und Eigenschaften, Eigenschaftennamen, Toolboxbezeichnungen, Standardfehlermeldungen und andere Zeichenfolgen, die dem Benutzer angezeigt werden können. Sie enthält auch Toolsymbole und Bilder für Bildformen.

Diese Datei ist an die integrierte Assembly gebunden und stellt die Standardwerte dieser Ressourcen bereit. Sie können Ihr DSL lokalisieren, indem Sie eine Satellitenassembly erstellen, die eine lokalisierte Version der Ressourcen enthält. Diese Version wird verwendet, wenn das DSL in einer Kultur installiert wird, die den lokalisierten Ressourcen entspricht. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.

DomainRelationships.cs

Jede Verknüpfung zwischen zwei Elementen in einem Modell wird durch eine Instanz einer Domänenbeziehungsklasse dargestellt. Alle Beziehungsklassen sind von ElementLink abgeleitet, das wiederum von ModelElement abgeleitet ist. 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 eine Multiplikation von 1...1 oder 1..*angeben, sollte der Benutzer gewarnt werden, dass mindestens eine Instanz der Beziehung erforderlich ist. Diese Datei enthält Validierungsbeschränkungen, die die Warnungen umsetzen. Der Link "1..1" zu einem einbettenden übergeordneten Element wird nicht überprüft.

Damit diese Einschränkungen ausgeführt werden können, müssen Sie eine der Uses...-Optionen im Knoten Editor\Validation des DSL-Explorers festgelegt haben. Weitere Informationen finden Sie unter "Überprüfung in einer Domain-Specific Sprache".

PropertiesGrid.cs

Diese Datei enthält nur Code, wenn Sie einen benutzerdefinierten Typdeskriptor an eine Domäneneigenschaft angefügt haben. Weitere Informationen finden Sie unter Anpassen des Eigenschaftenfensters.

SerializationHelper.cs

  • Eine Überprüfungsmethode, um sicherzustellen, dass keine zwei Elemente vom gleichen Moniker referenziert werden. Weitere Informationen finden Sie unter Anpassen der Dateispeicher- und XML-Serialisierung.

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

    Serializer.cs

    Eine Serialisierungsklasse für jede Domänenklasse, Beziehung, Form, Verbinder, Diagramm und Modell.

    Viele der Features dieser Klassen können durch die Einstellungen im DSL-Explorer unter Xml Serialization Behavior gesteuert werden.

    Shapes.cs

    Eine Klasse für jede Formklasse in der DSL-Definition. Die Formen werden von NodeShape abgeleitet. Weitere Informationen finden Sie unter Anpassen der Dateispeicher- und XML-Serialisierung.

    Um die generierten Methoden mit Ihren eigenen Methoden in einer partiellen Klasse außer Kraft zu setzen, setzen Sie Generates Double Derived für den Konnektor in der DSL-Definition. Um einen Konstruktor durch Ihren eigenen Code zu ersetzen, legen Sie has Custom Constructor fest.

    Um die Farbe und einige andere Stilmerkmale zur Laufzeit variabel zu gestalten, klicken Sie mit der rechten Maustaste auf die Klasse im DSL-Definitionsdiagramm, und zeigen Sie auf Belichtung hinzufügen.

    Um zusätzliche Stilmerkmale zur Laufzeit variabel zu machen, siehe zum Beispiel 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, das eine Gruppe mehrerer Objekte erstellt. Sie können z. B. ein Element definieren, das Objekte mit Unterkomponenten darstellt. Setzen Sie nach dem Ändern des Codes die experimentelle Instanz von Visual Studio zurück, um den Toolboxcache zu löschen.

Generierte Dateien im DslPackage-Projekt

DslPackage gekoppelt das DSL-Modell mit der Visual Studio-Shell, verwaltet die Fenster-, Toolbox- und Menübefehle. Die meisten Klassen werden doppelt abgeleitet, sodass Sie jede ihrer Methoden außer Kraft setzen können.

CommandSet.cs

Die Im Diagramm sichtbaren Menübefehle mit der rechten Maustaste. Sie können dieses Set anpassen oder erweitern. Diese Datei enthält den Code für die Befehle. Der Speicherort 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

YourDslDocData verwaltet das Laden und Speichern eines Modells in einer Datei und erstellt die Store-Instanz.

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

DocView.cs

YourDslDocView verwaltet das Fenster, in dem das Diagramm angezeigt wird. Sie können beispielsweise das Diagramm in ein Fensterformular einbetten:

Fügen Sie dem DslPackage-Projekt eine Benutzersteuerungsdatei hinzu. Fügen Sie einen Bereich hinzu, in dem das Diagramm angezeigt werden kann. Hinzufügen von Schaltflächen und anderen Steuerelementen Fügen Sie in der Codeansicht des Formulars den folgenden Code hinzu, und passen Sie die Namen an Ihr 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. Es erfüllt eine Standardschnittstelle, die Visual Studio zum Öffnen eines Editors verwendet, wenn Das DSL-Paket gestartet wird. Es wird im ProvideEditorFactory-Attribut in Package.cs referenziert.

GeneratedVSCT.vsct

Finden der Standardmenübefehle in Menüs, wie z. B. im Kontextmenü des Diagramms bei Rechtsklick, dem 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 Ihr DSL. Dies ist die Baumansicht des Modells, die der Benutzer neben dem Diagramm sieht.

Sie können z. B. außer Kraft setzen InsertTreeView() , um die Reihenfolge zu ändern, in der Elemente im Modell-Explorer angezeigt werden.

Wenn die Auswahl im Modell-Explorer mit der Diagrammauswahl synchronisiert werden soll, können Sie den folgenden Code verwenden:

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. Behandelt die Auswahl von Elementen im Explorer.

Package.cs

Diese Datei definiert, wie das DSL in Visual Studio integriert wird. Attribute der Paketklasse registrieren das DSL als den Handler für Dateien, die Ihre Dateierweiterung nutzen, definieren dessen Toolbox und geben an, wie ein neues Fenster geöffnet wird. Die Initialize()-Methode wird einmal aufgerufen, wenn das 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, um Ressourcen wie Symbole oder Bilder einzuschließen, stellen Sie sicher, dass die Ressource im VSIX-Build enthalten ist. Wählen Sie im Projektmappen-Explorer die Datei aus, und stellen Sie sicher, dass die Eigenschaft "In VSIX einschließen " lautet True.

Diese Datei steuert, wie das DSL in eine Visual Studio Integration Extension (VSIX) verpackt wird. Weitere Informationen finden Sie unter Deploying Domain-Specific Language Solutions.