Freigeben über


Überschreiben und Erweitern der generierten Klassen

Ihre DSL-Definition ist eine Plattform, auf der Sie leistungsstarke Tools erstellen können, die auf einer domänenspezifischen Sprache basieren. Viele Erweiterungen und Anpassungen können durch Überschreiben und Erweitern der Klassen vorgenommen werden, die aus der DSL-Definition generiert werden. Diese Klassen umfassen nicht nur die Domänenklassen, die Sie explizit im DSL-Definitionsdiagramm definiert haben, sondern auch andere Klassen, die die Toolbox, den Explorer, die Serialisierung usw. definieren.

Erweiterbarkeitsmechanismen

Es werden mehrere Mechanismen bereitgestellt, mit denen Sie den generierten Code erweitern können.

Überschreiben von Methoden in einer partiellen Klasse

Definitionen partieller Klassen ermöglichen die Definition einer Klasse an mehreren Orten. Dadurch können Sie den generierten Code von dem Code trennen, den Sie selbst schreiben. In Ihrem manuell geschriebenen Code können Sie Klassen außer Kraft setzen, die vom generierten Code geerbt werden.

Wenn Sie beispielsweise in Ihrer DSL-Definition eine Domänenklasse mit dem Namen Bookdefinieren, können Sie benutzerdefinierten Code schreiben, der Überschreibungsmethoden hinzufügt:

public partial class Book
{
   protected override void OnDeleting()
   {
      MessageBox.Show("Deleting book " + this.Title);
      base.OnDeleting();
   }
}

Hinweis

Für die Außerkraftsetzung von Methoden in einer generierten Klasse schreiben Sie Ihren Code immer in eine Datei, die von den generierten Dateien getrennt ist. In der Regel ist die Datei in einem Ordner mit dem Namen „CustomCode“ enthalten. Wenn Sie Änderungen am generierten Code vornehmen, gehen diese verloren, wenn Sie den Code aus der DSL-Definition neu generieren.

Zum Ermitteln der Methoden, die Sie außer Kraft setzen können, geben Sie override in die Klasse ein, gefolgt von einem Leerzeichen. In der IntelliSense-QuickInfo erfahren Sie, welche Methoden überschrieben werden können.

Double-Derived-Klassen

Die meisten Methoden in generierten Klassen werden von einem festen Klassensatz in den Modellierungsnamespaces geerbt. Einige Methoden werden jedoch im generierten Code definiert. Normalerweise bedeutet dies, dass Sie sie nicht außer Kraft setzen können; Sie können die Methoden, die in einer anderen partiellen Definition derselben Klasse definiert sind, nicht in einer partiellen Klasse überschreiben.

Trotzdem können Sie diese Methoden überschreiben, indem Sie das Flag Generates Double Derived für die Domänenklasse festlegen. Dies führt dazu, dass zwei Klassen generiert werden, wobei eine eine abstrakte Basisklasse der anderen ist. Alle Methoden- und Eigenschaftsdefinitionen befinden sich in der Basisklasse, und nur der Konstruktor befindet sich in der abgeleiteten Klasse.

Im Beispiel „Library.dsl“ ist für die Domäne CirculationBook die Eigenschaft Generates``Double Derived auf true festgelegt. Der generierte Code für diese Domänenklasse enthält zwei Klassen:

  • CirculationBookBase, eine abstrakte Klasse, die alle Methoden und Eigenschaften enthält.

  • CirculationBook, die von CirculationBookBase abgeleitet ist. Sie ist leer, mit Ausnahme ihrer Konstruktoren.

Zur Außerkraftsetzung einer Methode erstellen Sie eine partielle Definition der abgeleiteten Klasse, z. B. CirculationBook. Sie können sowohl die generierten Methoden als auch die vom Modellierungsframework geerbten Methoden überschreiben.

Sie können diese Methode mit allen Elementtypen verwenden, einschließlich Modellelementen, Beziehungen, Formen, Diagrammen und Connectors. Sie können auch Methoden anderer generierter Klassen außer Kraft setzen. Einige generierte Klassen, z. B. ToolboxHelper, werden immer doppelt abgeleitet.

Benutzerdefinierte Konstruktoren

Sie können einen Konstruktor nicht außer Kraft setzen. Auch in Double-Derived-Klassen muss sich der Konstruktor in der abgeleiteten Klasse befinden.

Wenn Sie einen eigenen Konstruktor bereitstellen möchten, können Sie dies tun, indem Sie in der DSL-Definition für die Domänenklasse Has Custom Constructor festlegen. Wenn Sie auf Alle Vorlagen transformieren klicken, enthält der generierte Code keinen Konstruktor für diese Klasse. Er enthält einen Aufruf des fehlenden Konstruktors. Dies verursacht einen Fehlerbericht, wenn Sie die Projektmappe erstellen. Doppelklicken Sie auf den Fehlerbericht, um einen Kommentar im generierten Code zu lesen, der erläutert, was Sie bereitstellen sollten.

Schreiben Sie eine partielle Klassendefinition in einer Datei, die von den generierten Dateien getrennt ist, und stellen Sie den Konstruktor bereit.

Gekennzeichnete Erweiterungspunkte

Ein gekennzeichneter Erweiterungspunkt ist ein Ort in der DSL-Definition, an dem Sie eine Eigenschaft oder ein Kontrollkästchen festlegen können, um anzugeben, dass Sie eine benutzerdefinierte Methode bereitstellen. Benutzerdefinierte Konstruktoren sind ein Beispiel. Weitere Beispiele sind das Festlegen von Kind einer Domäneneigenschaft auf „Berechnet“ oder „Benutzerdefinierter Speicher“ oder das Festlegen des Flages Is Custom in einem Verbindungs-Generator.

Wenn Sie das Flag festlegen und den Code noch mal generieren, tritt in jedem Fall ein Buildfehler auf. Doppelklicken Sie auf den Fehler, um einen Kommentar zu lesen, der erläutert, was Sie bereitstellen müssen.

Regeln

Mit dem Transaktions-Manager können Sie Regeln definieren, die vor dem Ende einer Transaktion ausgeführt werden, in der ein bestimmtes Ereignis aufgetreten ist, z. B. eine Änderung in einer Eigenschaft. Regeln werden in der Regel verwendet, um die Synchronisierung zwischen verschiedenen Elementen im Speicher aufrechtzuerhalten. Beispielsweise werden Regeln verwendet, um sicherzustellen, dass das Diagramm den aktuellen Zustand des Modells anzeigt.

Regeln werden auf Klassenbasis definiert, sodass Sie nicht über Code verfügen müssen, der die Regel für jedes Objekt registriert. Weitere Informationen finden Sie unter Regeln propagieren Änderungen im Modell.

Speicherereignisse

Der Modellierungsspeicher stellt einen Ereignismechanismus bereit, mit dem Sie auf bestimmte Arten von Änderungen im Speicher lauschen können, z. B. das Hinzufügen und Löschen von Elementen, Änderungen an Eigenschaftswerten usw. Die Ereignishandler werden nach Abschluss der Transaktion aufgerufen, in der die Änderungen vorgenommen wurden. In der Regel werden diese Ereignisse verwendet, um Ressourcen außerhalb des Speichers zu aktualisieren.

.NET-Ereignisse

Sie können einige Ereignisse für Shapes abonnieren. Sie können z. B. auf Mausklicks auf einem Shape lauschen. Sie müssen Code schreiben, der das Ereignis für jedes Objekt abonniert. Dieser Code kann in einer Außerkraftsetzung von InitializeInstanceResources() geschrieben werden.

Einige Ereignisse werden auf ShapeFields generiert, die verwendet werden, um Decorators auf einem Shape zu zeichnen. Ein Beispiel finden Sie unter Vorgehensweise: Abfangen eines Klicks auf ein Shape oder einen Decorator.

Diese Ereignisse treten normalerweise nicht innerhalb einer Transaktion auf. Sie sollten eine Transaktion erstellen, wenn Sie Änderungen im Speicher vornehmen möchten.