Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
Als auteur van een domeinspecifieke taal (DSL) kunt u validatiebeperkingen definiëren om te controleren of het model dat door de gebruiker is gemaakt zinvol is. Als uw DSL bijvoorbeeld toestaat dat gebruikers een familiestructuur van mensen en hun voorouders tekenen, kunt u een beperking schrijven die ervoor zorgt dat kinderen geboortedatums hebben na hun ouders.
U kunt de validatiebeperkingen uitvoeren wanneer het model wordt opgeslagen, wanneer het wordt geopend en wanneer de gebruiker de menuopdracht Valideren expliciet uitvoert. U kunt ook validatie uitvoeren onder programmabeheer. U kunt bijvoorbeeld validatie uitvoeren als reactie op een wijziging in een eigenschapswaarde of -relatie.
Validatie is met name belangrijk als u tekstsjablonen of andere hulpprogramma's schrijft die de modellen van uw gebruikers verwerken. Validatie zorgt ervoor dat de modellen voldoen aan de voorwaarden die door deze hulpprogramma's worden aangenomen.
Waarschuwing
U kunt ook toestaan dat validatiebeperkingen worden gedefinieerd in afzonderlijke extensies voor uw DSL, samen met opdrachten in het extensiemenu en gebarenhandlers. Gebruikers kunnen ervoor kiezen om deze extensies naast uw DSL te installeren. Zie Uw DSL uitbreiden met behulp van MEF voor meer informatie.
Validatie uitvoeren
Wanneer een gebruiker een model bewerkt, dat wil gezegd een exemplaar van uw domeinspecifieke taal, kunnen de volgende acties validatie uitvoeren:
Klik met de rechtermuisknop op het diagram en selecteer Alles valideren.
Klik met de rechtermuisknop op het bovenste knooppunt in de Explorer van uw DSL en selecteer Alles valideren
Sla het model op.
Open het model.
Daarnaast kunt u programmacode schrijven waarmee validatie wordt uitgevoerd, bijvoorbeeld als onderdeel van een menuopdracht of als reactie op een wijziging.
Validatiefouten worden weergegeven in het venster Foutenlijst . De gebruiker kan dubbelklikken op een foutbericht om de modelelementen te selecteren die de oorzaak van de fout zijn.
Validatiebeperkingen definiëren
U definieert validatiebeperkingen door validatiemethoden toe te voegen aan de domeinklassen of relaties van uw DSL. Wanneer de validatie wordt uitgevoerd, worden sommige of alle validatiemethoden uitgevoerd door de gebruiker of onder programmabeheer. Elke methode wordt toegepast op elk exemplaar van de klasse en er kunnen verschillende validatiemethoden in elke klasse zijn.
Elke validatiemethode rapporteert eventuele fouten die worden gevonden.
Opmerking
Bij validatiemethoden worden fouten gerapporteerd, maar wordt het model niet gewijzigd. Zie Alternatieven voor validatie als u bepaalde wijzigingen wilt aanpassen of voorkomen.
Een validatiebeperking definiëren
Validatie inschakelen in het knooppunt Editor\Validatie :
Open Dsl\DslDefinition.dsl.
Vouw in DSL Explorer het knooppunt Editor uit en selecteer Validatie.
Stel in het venster Eigenschappen de eigenschappen Gebruiken in op
true. Het is het handigst om al deze eigenschappen in te stellen.Klik op Alle sjablonen transformeren op de werkbalk Solution Explorer .
Schrijf gedeeltelijke klassedefinities voor een of meer van uw domeinklassen of domeinrelaties. Schrijf deze definities in een nieuw codebestand in het Dsl-project .
Voorvoegsel voor elke klasse met dit kenmerk:
[ValidationState(ValidationState.Enabled)]- Dit kenmerk schakelt standaard ook validatie in voor afgeleide klassen. Als u validatie voor een specifieke afgeleide klasse wilt uitschakelen, kunt u dit gebruiken
ValidationState.Disabled.
- Dit kenmerk schakelt standaard ook validatie in voor afgeleide klassen. Als u validatie voor een specifieke afgeleide klasse wilt uitschakelen, kunt u dit gebruiken
Voeg validatiemethoden toe aan de klassen. Elke validatiemethode kan elke naam hebben, maar één parameter van het type ValidationContext.
Deze moet worden voorafgegaan door een of meer
ValidationMethodkenmerken:[ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]De Validatiecategorieën geven op wanneer de methode wordt uitgevoerd.
Voorbeeld:
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);
}
}
Let op de volgende punten over deze code:
U kunt validatiemethoden toevoegen aan domeinklassen of domeinrelaties. De code voor deze typen is in Dsl\Generated Code\Domain*.cs.
Elke validatiemethode wordt toegepast op elk exemplaar van de klasse en de bijbehorende subklassen. In het geval van een domeinrelatie is elk exemplaar een koppeling tussen twee modelelementen.
Validatiemethoden worden niet toegepast in een bepaalde volgorde en elke methode wordt niet toegepast op de exemplaren van de klasse in een voorspelbare volgorde.
Het is meestal een slechte gewoonte voor een validatiemethode om de inhoud van het archief bij te werken, omdat dit tot inconsistente resultaten zou leiden. In plaats daarvan moet de methode een fout melden door aan te roepen
context.LogError,LogWarningofLogInfo.In de aanroep LogError kunt u een lijst met modelelementen of relatiekoppelingen opgeven die worden geselecteerd wanneer de gebruiker dubbelklikt op het foutbericht.
Zie Navigeren en een model bijwerken in Programmacode voor informatie over het lezen van het model in programmacode.
Het voorbeeld is van toepassing op het volgende domeinmodel. De relatie ParentsHaveChildren heeft rollen die Child en Parent heten.
Validatiecategorieën
In het ValidationMethodAttribute kenmerk geeft u op wanneer de validatiemethode moet worden uitgevoerd.
| Categorie | Execution |
|---|---|
| ValidationCategories | Wanneer de gebruiker de menuopdracht Valideren aanroept. |
| ValidationCategories | Wanneer het modelbestand wordt geopend. |
| ValidationCategories | Wanneer het bestand is opgeslagen. Als er validatiefouten zijn, krijgt de gebruiker de mogelijkheid om de opslagbewerking te annuleren. |
| ValidationCategories | Wanneer het bestand is opgeslagen. Als er fouten zijn opgetreden in methoden in deze categorie, wordt de gebruiker gewaarschuwd dat het mogelijk niet mogelijk is het bestand opnieuw te openen. Gebruik deze categorie voor validatiemethoden die testen op dubbele namen of id's, of andere voorwaarden die mogelijk fouten veroorzaken bij het laden. |
| ValidationCategories | Wanneer de methode ValidateCustom wordt aangeroepen. Validaties in deze categorie kunnen alleen worden aangeroepen vanuit programmacode. Zie Aangepaste validatiecategorieën voor meer informatie. |
Waar moet ik validatiemethoden plaatsen?
U kunt vaak hetzelfde effect bereiken door een validatiemethode op een ander type te plaatsen. U kunt bijvoorbeeld een methode toevoegen aan de klasse Person in plaats van de relatie ParentsHaveChildren en vervolgens door de koppelingen itereren:
[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)
{ ...
Validatiebeperkingen aggregeren. Als u validatie in een voorspelbare volgorde wilt toepassen, definieert u één validatiemethode voor een eigenaarsklasse, zoals het hoofdelement van uw model. Met deze techniek kunt u ook meerdere foutrapporten samenvoegen in één bericht.
Nadelen zijn dat de gecombineerde methode minder eenvoudig te beheren is en dat de beperkingen allemaal hetzelfde ValidationCategoriesmoeten hebben. We raden u daarom aan elke beperking in een afzonderlijke methode te houden, indien mogelijk.
Waarden doorgeven in de contextcache. De contextparameter bevat een woordenlijst waarin u willekeurige waarden kunt plaatsen. De woordenlijst blijft behouden gedurende de levensduur van de validatieuitvoering. Een bepaalde validatiemethode kan bijvoorbeeld het aantal fouten in de context behouden en deze gebruiken om te voorkomen dat het foutvenster wordt overspoeld met herhaalde berichten. Voorbeeld:
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( ... ); }
Validatie van multipliciteiten
Validatiemethoden voor het controleren van minimale multipliciteit worden automatisch gegenereerd voor uw DSL. De code wordt geschreven naar Dsl\Generated Code\MultiplicityValidation.cs. Deze methoden worden van kracht wanneer u validatie inschakelt in het knooppunt Editor\Validatie in DSL Explorer.
Als u de multipliciteit van een rol van een domeinrelatie instelt op 1..*of 1..1, maar de gebruiker geen koppeling van deze relatie maakt, wordt er een validatiefoutbericht weergegeven.
Als uw DSL bijvoorbeeld de klassen Persoon en Stad en een relatie PersoonWoontInStad heeft met een relatie 1..\* bij de rol Stad, wordt er een foutbericht weergegeven voor elke Persoon die geen Stad heeft.
Validatie uitvoeren vanuit programmacode
U kunt validatie uitvoeren door een Validatiecontroller te openen of te maken. Als u wilt dat de fouten worden weergegeven aan de gebruiker in het foutvenster, gebruikt u de Validatiecontroller die is gekoppeld aan docdata van uw diagram. Als u bijvoorbeeld een menuopdracht schrijft, CurrentDocData.ValidationController is deze beschikbaar in de opdrachtsetklasse:
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;
...
Zie Een opdracht toevoegen aan het snelmenu voor meer informatie.
U kunt ook een afzonderlijke validatiecontroller maken en de fouten zelf beheren. Voorbeeld:
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) { ... }
}
Validatie uitvoeren wanneer een wijziging plaatsvindt
Als u ervoor wilt zorgen dat de gebruiker onmiddellijk wordt gewaarschuwd als het model ongeldig wordt, kunt u een winkelgebeurtenis definiëren waarmee validatie wordt uitgevoerd. Zie Gebeurtenishandlers Wijzigingen doorgeven buiten het model voor meer informatie over het opslaan van gebeurtenissen.
Voeg naast de validatiecode een aangepast codebestand toe aan uw DslPackage-project , met inhoud die vergelijkbaar is met het volgende voorbeeld. Deze code maakt gebruik van de ValidationController code die is gekoppeld aan het document. Deze controller geeft de validatiefouten weer in de visual Studio-foutenlijst.
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);
}
}
}
De handlers worden ook aangeroepen na het ongedaan maken of opnieuw uitvoeren van bewerkingen die van invloed zijn op de koppelingen of elementen.
Aangepaste validatiecategorieën
Naast de standaardvalidatiecategorieën, zoals Menu en Openen, kunt u uw eigen categorieën definiëren. U kunt deze categorieën aanroepen vanuit programmacode. De gebruiker kan deze niet rechtstreeks aanroepen.
Een typisch gebruik voor aangepaste categorieën is het definiëren van een categorie waarmee wordt getest of het model voldoet aan de voorwaarden van een bepaald hulpmiddel.
Als u een validatiemethode aan een bepaalde categorie wilt toevoegen, moet u deze vooraf laten gaan door een kenmerk als volgt te gebruiken:
[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)]
private void TestForCircularLinks(ValidationContext context)
{...}
Opmerking
U kunt een methode vooraf laten gaan met zoveel [ValidationMethod()] kenmerken als u wilt. U kunt een methode toevoegen aan zowel aangepaste als standaardcategorieën.
Een aangepaste validatie aanroepen:
// Invoke all validation methods in a custom category:
validationController.ValidateCustom
(store, // or a list of model elements
"PreconditionsForGeneratePartsList");
Alternatieven voor validatie
Validatiebeperkingen rapporteren fouten, maar wijzigen het model niet. Als u in plaats daarvan wilt voorkomen dat het model ongeldig wordt, kunt u andere technieken gebruiken.
Deze technieken worden echter niet aanbevolen. Het is meestal beter om de gebruiker te laten beslissen hoe een ongeldig model moet worden gecorrigeerd.
Pas de wijziging aan om het model te herstellen naar geldigheid. Als de gebruiker bijvoorbeeld een eigenschap instelt boven het toegestane maximum, kunt u de eigenschap opnieuw instellen op de maximumwaarde. Hiervoor definieert u een regel. Voor meer informatie, zie Hoe regels veranderingen binnen het model doorgeven.
De transactie terugdraaien als er een ongeldige wijziging wordt uitgevoerd. U kunt ook een regel voor dit doel definiëren, maar in sommige gevallen is het mogelijk om een eigenschapshandler OnValueChanging() te overschrijven of om een methode zoals OnDeleted(). te overschrijven. Om een transactie terug te draaien, gebruikt u this.Store.TransactionManager.CurrentTransaction.Rollback().. Voor meer informatie, zie de wijzigingshandlers voor domeineigenschapwaarden.
Waarschuwing
Zorg ervoor dat de gebruiker weet dat de wijziging is aangepast of teruggedraaid. Gebruik bijvoorbeeld System.Windows.Forms.MessageBox.Show("message").