Validierung in einer domänenspezifischen Sprache
Als Autor einer domänenspezifischen Sprache (DSL) können Sie Validierungseinschränkungen definieren, um sicherzustellen, dass das Modell, das vom Benutzer erstellte sinnvoll ist.Wenn z. B. das DSL Benutzer einen Stammbaum von Personen und deren Vorgängern zu zeichnen, können Sie schreiben eine Einschränkung, die gewährleistet, dass untergeordnete Elemente Birth Datumsangaben nach ihren übergeordneten Elementen verfügen.
Sie können die Validierungseinschränkungen ausführen lassen, wenn das Modell gespeichert ist, geöffnet wird und wenn der Benutzer explizit den Überprüfen Menübefehl ausführt.Sie können auch die Steuerung Programm unter Validierung ausführen.Beispielsweise können Sie die Validierung als Reaktion auf eine Änderung eines Eigenschaftswerts oder in einer Beziehung ausgeführt werden.
Die Validierung ist besonders wichtig, wenn Sie Textvorlagen oder andere Tools programmieren, die die Modelle des Benutzers verarbeiten.Die Validierung wird sichergestellt, dass die Modelle die Vorbedingungen erfüllen, die von diesen Tools angenommen werden.
Vorsicht |
---|
Sie können die in separaten Erweiterungen, die zusammen mit DSL menübefehlen und Gestenhandlern Erweiterungsmethoden definiert werden soll können auch Validierungseinschränkungen.Benutzer können diese Erweiterungen zusätzlich zum DSL zu installieren.Weitere Informationen finden Sie unter Erweitern von DSL mittels MEF. |
Ausgeführte Validierung
Wenn ein Benutzer ein Modell, d. h. eine Instanz einer domänenspezifischen Sprache verarbeitet, können die folgenden Aktionen Validierung ausführen:
Klicken Sie mit der rechten Maustaste auf das Diagramm, und wählen Sie Alle überprüfen.
Klicken Sie mit der rechten Maustaste auf den Knoten der obersten Ebene im Explorer des DSL und des ausgewählten Alle überprüfen
Speichern Sie das Modell.
Öffnen Sie das Modell.
Darüber hinaus können Sie Programmcode schreiben, der die Validierung, z. B. als Teil eines Menübefehls oder als Reaktion auf eine Änderung ausgeführt werden soll.
Alle Validierungsfehler werden im Fenster Fehlerliste .Der Benutzer kann eine Fehlermeldung doppelklicken, um die Modellelemente auszuwählen, die die Ursache des Fehlers handelt.
Definieren Validierungs-Einschränkungen
Validierungseinschränkungen definieren Sie mithilfe von Validierungsmethoden zu Domänen Klassen oder DSL des Beziehungen hinzufügen.Wenn die Validierung, entweder durch den Benutzer oder unter Programm die Steuerung bedingungslos ausgeführt wird, werden einige oder alle Validierungsmethoden ausgeführt.Jede Methode wird für jede Instanz der Klasse angewendet, und es kann eine Reihe von Validierungsmethoden in jeder Klasse geben.
In jeder Validierungsmethode alle gefundenen Fehler.
Hinweis |
---|
Fehler beim methoden-Berichts Validierung ändern, aber nicht das Modell.Wenn Sie bestimmte Änderungen anpassen oder verhindern möchten, finden Sie weitere Informationen Alternativen zur Validierung. |
So fügen Sie eine Validierung KEY-Einschränkung definieren
Aktivieren Sie die Validierung im Editor\Validation Knoten:
Öffnen Sie Dsl\DslDefinition.dsl.
In DSL-Explorer erweitern Sie den Knoten Editor und wählen Sie Validierungaus.
Legen Sie im Eigenschaftenfenster die Eigenschaften trueVerwenden fest.Dies ist besonders bequemsten alle diese Eigenschaften festzulegen.
Klicken Sie auf der Symbolleiste des Projektmappen-Explorers auf Alle Vorlagen transformieren .
Schreiben Sie partielle Klassendefinitionen für eine oder mehrere Domänen Klassen oder Domänen-Verhältnisse.Schreiben Sie diese Definitionen in eine neue Codedatei im Dsl Projekt.
Präfix jede Klasse mit diesem Attribut:
[ValidationState(ValidationState.Enabled)]
- Standardmäßig aktiviert dieses Attribut auch die Validierung für abgeleitete Klassen.Wenn Sie die Validierung für eine bestimmte abgeleitete Klasse deaktivieren möchten, können Sie ValidationState.Disabledverwenden.
Hinzufügen von Validierungsmethoden den Klassen hinzufügen.Jede Validierungsmethode kann einen beliebigen Namen aufweisen, hat jedoch einen Parameter des Typs ValidationContext.
Er muss mit einem oder mehreren Attributen ValidationMethod vorangestellt werden:
[ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]
Der ValidationCategories geben an, wann die Methode ausgeführt wird.
Beispiele:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
// Allow validation methods in this class:
[ValidationState(ValidationState.Enabled)]
// In this DSL, ParentsHaveChildren is a domain relationship
// from Person to Person:
public partial class ParentsHaveChildren
{
// Identify the method as a validation method:
[ValidationMethod
( // Specify which events cause the method to be invoked:
ValidationCategories.Open // On file load.
| ValidationCategories.Save // On save to file.
| ValidationCategories.Menu // On user menu command.
)]
// This method is applied to each instance of the
// type (and its subtypes) in a model:
private void ValidateParentBirth(ValidationContext context)
{
// In this DSL, the role names of this relationship
// are "Child" and "Parent":
if (this.Child.BirthYear < this.Parent.BirthYear
// Allow user to leave the year unset:
&& this.Child.BirthYear != 0)
{
context.LogError(
// Description:
"Child must be born after Parent",
// Unique code for this error:
"FAB001ParentBirthError",
// Objects to select when user double-clicks error:
this.Child,
this.Parent);
}
}
Beachten Sie die folgenden Punkte zu den folgenden Code:
Sie können Validierungsmethoden Domänen oder Domänen-Verhältnissen Klassen hinzufügen.Der Code für diese Typen ist in Dsl\Generated Code\Domain*.cs.
Jede Validierungsmethode wird für jede Instanz der Klasse und ihrer Unterklassen übernommen.Im Falle eines Domänen-Verhältnisses ist jede Instanz ein Link zwischen zwei Modellelementen.
Validierungsmethoden sind nicht in einer bestimmten Reihenfolge angewendet, und jede Methode wird nicht an Instanzen der Klasse in einer beliebigen vorhersagbaren Reihenfolge angewendet.
Es ist normalerweise ungültiges üblich, sodass eine Validierungsmethode Inhalt aktualisiert den Speicher, da dies zu inkonsistenten Ergebnissen führen würde.Stattdessen sollte die Methode jeder Fehler melden, indem sie context.LogError, LogWarning oder LogInfoaufruft.
Im LogError-Aufruf können Sie eine Liste von Modellelementen oder Verhältnis-Links bereitstellen, die ausgewählt werden, wenn der Benutzer auf die Fehlermeldung doppelklicken.
Weitere Informationen dazu, wie Sie das Modell im Programmcode finden Sie unter Navigieren in und Aktualisieren von Modellen im Programmcodeliest.
Das Beispiel gilt Folgendes Domänenmodell auf.Das ParentsHaveChildren-Verhältnis verfügt über Rollen, die mit der Bezeichnung untergeordnete Elemente und übergeordnete Element befinden.
Validierungs-Kategorien
Im ValidationMethod-Attribut geben Sie an, wann die Validierungsmethode ausgeführt werden soll.
Kategorie |
Ausführung |
---|---|
Wenn der Benutzer im Menü Überprüfen aufruft. |
|
Wenn die Modelldatei geöffnet ist. |
|
Sobald die Datei gespeichert wird.Wenn Validierungsfehler vorliegt, muss der Benutzer die Möglichkeit Abbrechens des Speichervorgangs angegeben. |
|
Sobald die Datei gespeichert wird.Sind Fehler von den Methoden in dieser Kategorie vorhanden ist, wird der Benutzer gewarnt, dass es nicht möglich ist, die Datei zu öffnen. Verwenden Sie diese Kategorie für Validierungsmethoden, die für doppelte Namen oder IDs testen, oder andere Bedingungen, die möglicherweise Ladefehler verursacht hat. |
|
Wenn die ValidateCustom-Methode aufgerufen wird.Validierungen in dieser Kategorie können nur aus Programmcode aufgerufen werden. Weitere Informationen finden Sie unter Benutzerdefinierte Validierungs-Kategorien. |
Bei Verwendung Validierungs-Methoden platziert
Sie können häufig denselben Effekt erzielen, indem Sie eine Validierungsmethode auf einen anderen Typ einfügen.Sie können beispielsweise eine Methode mit der anstelle des ParentsHaveChildren-Verhältnisses Klasse Person hinzu, und positionieren diese durch die Links durchlaufen:
[ValidationState(ValidationState.Enabled)]
public partial class Person
{[ValidationMethod
( ValidationCategories.Open
| ValidationCategories.Save
| ValidationCategories.Menu
)
]
private void ValidateParentBirth(ValidationContext context)
{
// Iterate through ParentHasChildren links:
foreach (Person parent in this.Parents)
{
if (this.BirthYear <= parent.BirthYear)
{ ...
Validierungseinschränkungen aggregieren. Um die Validierung auf vorhersehbare Reihenfolge anzuwenden, definieren Sie eine einzelne Validierungsmethode auf einer Besitzerklasse, sodass das Stammelement des Modells.Diese Technik können Sie auch mehrere Berichte des Fehlers in eine einzelne Nachricht aggregieren.
Nachteile liegen, dass die kombinierte weniger Methode einfach zu verwalten ist und dass alle Einschränkungen gleiche ValidationCategoriesaufweisen müssen.Es empfiehlt sich daher, dass Sie eine Einschränkung in einer separaten Methode beibehalten, sofern dies möglich ist.
Werte im Assemblycache des Kontexts übergeben. Der Kontextparameter ist ein Wörterbuch, in dem Sie beliebige Werte einfügen können.Das Wörterbuch permanent ist für die Dauer der Ausführung der Validierung.Eine bestimmte Validierungsmethode kann eine Fehlerzahl an den Kontext beispielsweise, und sie verwenden, um das Fenster mit wiederholten Meldungen, Fehler zu überschwemmen zu vermeiden.Beispiele:
List<ParentsHaveChildren> erroneousLinks;
if (!context.TryGetCacheValue("erroneousLinks", out erroneousLinks))
erroneousLinks = new List<ParentsHaveChildren>();
erroneousLinks.Add(this);
context.SetCacheValue("erroneousLinks", erroneousLinks);
if (erroneousLinks.Count < 5) { context.LogError( ... ); }
Validierung von Multiplizitäten
Validierungsmethoden für die Überprüfung der minimalen Multiplizität werden automatisch für das DSL generiert.Dsl\Generated Code\MultiplicityValidation.csder Code geschrieben wird.Diese Methoden treten in Kraft, wenn Sie eine Validierung im Editor\Validierung Knoten in DSL-Explorer aktivieren.
Wenn Sie die Multiplizität einer Rolle eines Domänen-Verhältnisses, um 1. * oder 1..1 sein, jedoch keine Verbindung dieses Beziehung erstellt wird, wird eine Validierungsfehlermeldung.
Wenn z. B. das DSL Klassen Person und Stadt hat, und eine Beziehung PersonLivesInTown zu einer Beziehung 1..* Rolle bei der Stadt, dann für jede Person, die keine Stadt verfügt, wird eine Fehlermeldung angezeigt.
Ausgeführte Validierung aus Programmcode
Sie können eine Validierung durchführen, indem Sie ein ValidationController zugreifen oder erstellen.Wenn Sie die Fehler für den Benutzer im Fehlerfenster angezeigt werden soll, verwenden Sie das ValidationController, das dem DocData des Diagramms angefügt wird.Wenn Sie z. B. einen Menübefehl schreiben, ist CurrentDocData.ValidationController in der festgelegten Klasse des Befehls verfügbar:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
partial class MyLanguageCommandSet
{
private void OnMenuMyContextMenuCommand(object sender, EventArgs e)
{
ValidationController controller = this.CurrentDocData.ValidationController;
...
Weitere Informationen finden Sie unter Gewusst wie: Hinzufügen eines Befehls zum Kontextmenü.
Sie können einen separaten controller Validierung erstellen und verwalten die Fehler auftreten.Beispiele:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
Store store = ...;
VsValidationController validator = new VsValidationController(s);
// Validate all elements in the Store:
if (!validator.Validate(store, ValidationCategories.Save))
{
// Deal with errors:
foreach (ValidationMessage message in validator.ValidationMessages) { ... }
}
Ausgeführte Validierung stattfindet, wenn eine Änderung
Wenn Sie überprüfen möchten, ob der Benutzer sofort gewarnt wird, wenn das Modell nicht gültig ist, können Sie ein Speicher für Auswahlereignisse definieren, die Validierung ausführt.Weitere Informationen zu Speicher von Ereignissen finden Sie unter Ereignishandler propagieren Änderungen außerhalb des Modells.
Neben dem Validierungscode fügen Sie der Codedatei eine benutzerdefinierte DslPackage Projekt mit ähnlichem dem folgenden Beispiel zufriedenem hinzu.In diesem Code wird ValidationController , der an das Dokument angefügt wird.Dieser Controller enthält die Validierungsfehler in der Visual Studio Fehlerliste angezeigt.
using System;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
namespace Company.FamilyTree
{
partial class FamilyTreeDocData // Change name to your DocData.
{
// Register the store event handler:
protected override void OnDocumentLoaded()
{
base.OnDocumentLoaded();
DomainClassInfo observedLinkInfo = this.Store.DomainDataDirectory
.FindDomainClass(typeof(ParentsHaveChildren));
DomainClassInfo observedClassInfo = this.Store.DomainDataDirectory
.FindDomainClass(typeof(Person));
EventManagerDirectory events = this.Store.EventManagerDirectory;
events.ElementAdded
.Add(observedLinkInfo, new EventHandler<ElementAddedEventArgs>(ParentLinkAddedHandler));
events.ElementDeleted.Add(observedLinkInfo, new EventHandler<ElementDeletedEventArgs>(ParentLinkDeletedHandler));
events.ElementPropertyChanged.Add(observedClassInfo, new EventHandler<ElementPropertyChangedEventArgs>(BirthDateChangedHandler));
}
// Handler will be called after transaction that creates a link:
private void ParentLinkAddedHandler(object sender,
ElementAddedEventArgs e)
{
this.ValidationController.Validate(e.ModelElement,
ValidationCategories.Save);
}
// Called when a link is deleted:
private void ParentLinkDeletedHandler(object sender,
ElementDeletedEventArgs e)
{
// Don't apply validation to a deleted item!
// - Validate store to refresh the error list.
this.ValidationController.Validate(this.Store,
ValidationCategories.Save);
}
// Called when any property of a Person element changes:
private void BirthDateChangedHandler(object sender,
ElementPropertyChangedEventArgs e)
{
Person person = e.ModelElement as Person;
// Not interested in changes in other properties:
if (e.DomainProperty.Id != Person.BirthYearDomainPropertyId)
return;
// Validate all parent links to and from the person:
this.ValidationController.Validate(
ParentsHaveChildren.GetLinksToParents(person)
.Concat(ParentsHaveChildren.GetLinksToChildren(person))
, ValidationCategories.Save);
}
}
}
Die Handler werden auch nach Wiederholungsvorgänge oder Undo aufgerufen, die die Links oder die Elemente beeinflussen.
Benutzerdefinierte Validierungs-Kategorien
Zusätzlich zu den standardmäßigen validierungs Kategorien und öffnen Sie das Menü, können Sie definieren Kategorien verfügen.Sie können diese Kategorien aus Programmcode aufrufen.Der Benutzer kann sie nicht direkt aufrufen.
Ein typisches Anwendungsbeispiel für benutzerdefinierte Kategorien besteht darin, eine Kategorie zu definieren, die testet, ob das Modell die Vorbedingungen eines bestimmten Tools erfüllt.
So erstellen Sie eine Validierungsmethode einer bestimmten Kategorie hinzufügen, kann es mit einem Präfix dieses Attribut:
[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)]
private void TestForCircularLinks(ValidationContext context)
{...}
Hinweis |
---|
Sie können Präfix eine Methode mit [ValidationMethod()]-Attributen.Sie können eine standardmäßige und benutzerdefinierte Methode den Kategorien hinzufügen. |
So erstellen Sie eine benutzerdefinierte Validierung aufrufen:
// Invoke all validation methods in a custom category:
validationController.ValidateCustom
(store, // or a list of model elements
"PreconditionsForGeneratePartsList");
Alternativen zur Validierung
Fehler beim einschränkungs-Berichts Validierung ändern, aber nicht das Modell.Wenn Sie stattdessen das Modell verhindern möchten, die nicht gültig ist, können Sie andere Techniken verwenden.
Diese Techniken sind jedoch nicht empfohlen.Es ist normalerweise besser, den Benutzer entscheiden können, wie ein ungültiges Modell korrigiert.
Passen Sie die Änderung, um die Gültigkeit des Modells wiederherzustellen. Wenn z. B. die Benutzer legt eine Eigenschaft über dem zulässigen Maximalwert, die Eigenschaft auf den maximalen Wert zurücksetzen können.Hierzu definieren Sie eine Regel.Weitere Informationen finden Sie unter Regeln propagieren Änderungen im Modell .
Setzen Sie die Transaktion ausgeführt, wenn eine ungültige Änderungen versucht wurden. Sie können auch eine Regel für diesen Zweck definieren, aber in einigen Fällen ist es möglich, einen Eigenschaft für **OnValueChanging()**zu überschreiben oder eine Methode wie OnDeleted(). zu überschreiben, um eine Transaktion zurücksetzen, sieht die Verwendung this.Store.TransactionManager.CurrentTransaction.Rollback(). Weitere Informationen Handler für Wertänderungen von Domäneneigenschaften.
Vorsicht |
---|
Stellen Sie sicher, dass der Benutzer weiß, dass die Änderung passt oder ein Rollback ausgeführt wird.Verwenden Sie z. System.Windows.Forms.MessageBox.Show("message"). |
Siehe auch
Konzepte
Navigieren in und Aktualisieren von Modellen im Programmcode
Ereignishandler propagieren Änderungen außerhalb des Modells