Condividi tramite


Convalida in un linguaggio specifico di dominio

L'autore di un linguaggio specifico di dominio (DSL), è possibile definire vincoli di convalida per verificare che il modello creato dall'utente sia significativo.Ad esempio, se il modello DSL consente agli utenti estraggano una struttura ad albero genealogico di persone e dei relativi predecessori, è possibile scrivere un vincolo che garantisce che gli elementi figlio dispongono di data di nascita dopo i relativi elementi padre.

È possibile disporre i vincoli di convalida di esecuzione quando il modello viene salvato, quando viene aperto e quando l'utente esegue esplicitamente convalidare comando di menu.È possibile eseguire la convalida nel controllo del programma.Ad esempio, è possibile eseguire la convalida in risposta a una modifica in un valore di proprietà o in una relazione.

La convalida è particolarmente importante quando si scrivono modelli di testo o altri strumenti che elaborano i modelli degli utenti.La convalida assicura che i modelli compiano precondizioni precondizioni dagli strumenti.

Nota di avvisoAttenzione

È anche possibile consentire ai vincoli di convalida siano definiti nelle estensioni separate al modello DSL, con i comandi di menu di estensione e gestori movimenti.Gli utenti possono scegliere di installare queste estensioni oltre al modello DSL.Per ulteriori informazioni, vedere Estendere il DSL mediante MEF.

convalida in esecuzione

Quando un utente modifica un modello, ovvero, un'istanza del linguaggio specifico di dominio, le azioni riportate di seguito possono eseguire la convalida:

  • Fare clic con il pulsante destro del mouse sul diagramma e scegliere convalidare tutti.

  • Fare clic con il pulsante destro del mouse sul nodo principale in Esplora Risorse del linguaggio DSL e selezionare convalidare tutti

  • salvare il modello.

  • aprire il modello.

  • Inoltre, è possibile scrivere codice programma che esegue la convalida, ad esempio, come parte di un comando di menu o in risposta a una modifica.

Tutti gli errori di convalida saranno visualizzate in Elenco errori finestra.L'utente può fare doppio clic su un messaggio di errore per selezionare gli elementi del modello che sono la causa.

Definizione dei vincoli di convalida

Definire vincoli di convalida aggiungendo metodi di convalida alle classi di dominio o alle relazioni di DSL.Quando la convalida viene eseguita, con l'utente o sotto il controllo del programma, alcuni o tutti i metodi di convalida vengono eseguiti.Ogni metodo viene applicato a ogni istanza della classe e possono essere presenti diversi metodi di convalida in ogni classe.

Ogni metodo di convalida vengono riportati gli eventuali errori rilevati.

[!NOTA]

I metodi di convalida indicano errori, ma non modificare il modello.Se si desidera regolare o impedire determinate modifiche, vedere alternative a convalida.

Per definire un vincolo di convalida

  1. Per abilitare la convalida in Editor\Validation nodo:

    1. Aprire Dsl\DslDefinition.dsl.

    2. Nel modello DSL Esplora Soluzioni, espandere editor il nodo e selezionare convalida.

    3. Nella Finestra Proprietà, impostare Utilizzo proprietà di true.È più pratico per configurare tutte queste proprietà.

    4. Fare clic su Trasformazione di tutti i modelli nella barra degli strumenti di Esplora soluzioni.

  2. Scrivere le definizioni di classe parziale per uno o più delle classi di dominio o di relazioni di dominio.scrivere queste definizioni in un nuovo file di codice in Dsl progetto.

  3. A ogni classe con questo attributo:

    [ValidationState(ValidationState.Enabled)]
    
    • Per impostazione predefinita, questo attributo viene abilitata la convalida per le classi derivate.Se si desidera disabilitare la convalida per una classe derivata specifica, è possibile utilizzare ValidationState.Disabled.
  4. Aggiungere i metodi di convalida alle classi.Ogni metodo di convalida può avere qualsiasi nome, ma dispone di un parametro di tipo ValidationContext.

    Deve essere preceduto da uno o più ValidationMethod attributi:

    [ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]
    

    Il ValidationCategories specifica quando il metodo viene eseguito.

Di seguito è riportato un esempio:

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);
    }
  }

Tenere presenti le informazioni seguenti sul codice seguente:

  • È possibile aggiungere i metodi di convalida alle classi di dominio o alle relazioni di dominio.Il codice per questi tipi è in Dsl\Generated Code\Domain*.cs.

  • Ogni metodo di convalida viene applicato a ogni istanza della classe e delle sottoclassi.Nel caso di una relazione di dominio, ogni istanza è un collegamento tra due elementi del modello.

  • I metodi di convalida non vengono applicate in ordine specificato e ogni metodo non si applica alle istanze della classe in ordine previsto.

  • È utile in genere errata per un metodo di convalida verrà aggiornato il contenuto dell'archivio, poiché questo condurrebbe ai risultati incoerenti.Invece, il metodo viene segnalato un errore chiamando context.LogError, LogWarning o LogInfo.

  • Nella chiamata di LogError, è possibile fornire un elenco di elementi del modello o dei collegamenti di relazione che verranno selezionati quando l'utente fa doppio clic sul messaggio di errore.

  • Per informazioni su come leggere il modello nel codice del programma, vedere Esplorazione e aggiornamento di un modello nel codice del programma.

Nell'esempio viene applicato il seguente modello di dominio.La relazione di ParentsHaveChildren con ruoli che sono denominati Child e padre.

Diagramma della definizione DSL: modello di albero genealogico

categorie di convalida

in ValidationMethod attributo, specificare quando il metodo di convalida deve essere eseguito.

Categoria

Esecuzione

Menu

Quando l'utente richiama il comando del menu convalida.

Open

Quando il file di modello viene aperto.

Save

Quando il file viene salvato.Se sono presenti errori di convalida, l'utente verrà fornito l'opzione di annullare l'operazione di salvataggio.

Load

Quando il file viene salvato.Se sono presenti errori dai metodi in questa categoria, l'utente viene visualizzato un avviso che potrebbe non essere possibile riaprire il file.

Utilizzare questa categoria per i metodi di convalida che testano per i nomi duplicati o ID, o altre condizioni che possono provocare errori di caricamento.

Custom

Quando il metodo di ValidateCustom viene chiamato.Le convalide in questa categoria possono essere richiamati solo dal codice programma.

Per ulteriori informazioni, vedere categorie personalizzate di convalida.

dove posizionare i metodi di convalida

È possibile ottenere spesso lo stesso risultato inserendo un metodo di convalida in un tipo diverso.Ad esempio, è possibile aggiungere un metodo alla classe di persona anziché la relazione di ParentsHaveChildren e si fa scorrere i collegamenti:

[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)
        { ...

Per aggregare i vincoli di convalida. Per applicare la convalida in modo prevedibile, definire un singolo metodo di convalida su una classe proprietario, tale elemento radice del modello.Questa tecnica consente di aggregare più i report di errore in un singolo messaggio.

Gli svantaggi sono che il metodo combinato è meno facile manutenibilità e che i vincoli devono tutti avere lo stesso ValidationCategories.Pertanto si consiglia di conservare ogni vincolo in un metodo separato se possibile.

Passare i valori nella cache del contesto. Il parametro di contesto ha un dizionario in cui è possibile inserire i valori arbitrari.Il dizionario viene mantenuto per la durata dell'esecuzione di convalida.Un metodo di convalida particolare potrebbe, ad esempio, mantenere un errore per importare il contesto e utilizzarlo per evitare il sovraccarico la finestra di errore dai messaggi ripetuti.Di seguito è riportato un esempio:

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( ... ); }

Convalida delle molteplicità

I metodi di convalida per verificare la molteplicità minima generati automaticamente per il linguaggio DSL.Il codice scritto a Dsl\Generated Code\MultiplicityValidation.cs.Questi metodi hanno effetto quando si abilita la convalida in editor \Validation nodo nel modello DSL Esplora Risorse.

Se si imposta la molteplicità di ruolo di una relazione di dominio che può essere 1. * o 1..1, ma l'utente non crea un collegamento di questa relazione, un messaggio di errore di convalida verrà visualizzato.

Ad esempio, se il modello DSL è la persona e città delle classi e una relazione PersonLivesInTown con una relazione 1 *. il ruolo di città, quindi per ogni persona che non dispone di città, verrà visualizzato un messaggio di errore.

Convalida in esecuzione dal codice programma

È possibile eseguire la convalida accesso o creando un ValidationController.Se si desidera che gli errori da visualizzare nella finestra di errore, utilizzare il ValidationController associato al DocData del diagramma.Ad esempio, se si scrive un comando di menu, CurrentDocData.ValidationController è disponibile nella classe con set di comando:

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; 
...

Per ulteriori informazioni, vedere Procedura: aggiungere un comando al menu di scelta rapida.

È inoltre possibile creare un controller diverso di convalida e gestire gli errori manualmente.Di seguito è riportato un esempio:

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) { ... }
}

Convalida in esecuzione quando si verifica una modifica

Se si desidera assicurarsi che sia visualizzato un avviso immediatamente se il modello diventa non valido, è possibile definire un evento dell'archivio che esegue la convalida.Per ulteriori informazioni sugli eventi dell'archivio, vedere I gestori eventi propagano le modifiche al di fuori del modello.

Oltre al codice di convalida, aggiungere un file di codice personalizzato a DslPackage proiettare, con contenuto simile al seguente.questo codice utilizza ValidationController che viene associato al documento.Questo controller visualizzare gli errori di convalida in Visual Studio elenco degli errori.

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);
    }
  }
} 

I gestori vengono chiamati dopo le operazioni di annullamento o ripristino che influiscono sui collegamenti o gli elementi.

categorie personalizzate di convalida

Oltre alle categorie standard di convalida, ad esempio menu e aprire, è possibile definire diventi proprietaria delle categorie.È possibile richiamare queste categorie dal codice programma.l'utente non può richiamarli direttamente.

Un utilizzo tipico delle categorie personalizzate è definire una categoria che verifica se il modello soddisfa le precondizioni di uno strumento specifico.

Per aggiungere un metodo di convalida a una categoria specifica, premetterla con un attributo come segue:

[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)] 
private void TestForCircularLinks(ValidationContext context) 
{...}

[!NOTA]

È possibile anteporre a un metodo con un massimo [ValidationMethod()] attributi desiderato.È possibile aggiungere un metodo alle categorie personalizzate che standard.

Per richiamare una convalida personalizzata:

// Invoke all validation methods in a custom category: 
validationController.ValidateCustom
  (store, // or a list of model elements
   "PreconditionsForGeneratePartsList");

alternative a convalida

I vincoli di convalida indicano errori, ma non modificare il modello.Se, invece, si desidera impedire il modello diventa non valido, è possibile utilizzare altre tecniche.

Tuttavia, queste tecniche non è consigliata.In genere è preferibile lasciare l'utente decidere come correggere un modello non valido.

regolare la modifica per ripristinare il modello a validità. Ad esempio, seutente una proprietà al massimo consentito, sarà possibile reimpostare la proprietà sul valore massimo.A tale scopo, definire una regola.Per ulteriori informazioni, vedere Le regole propagano le modifiche all'interno del modello.

Viene eseguito il rollback della transazione se una modifica non valida viene tentata. È possibile inoltre definire una regola a questo scopo, ma in alcuni casi è possibile eseguire l'override di un gestore della proprietà OnValueChanging(), o eseguire l'override di un metodo come OnDeleted(). Per eseguire il rollback della transazione, utilizzano this.Store.TransactionManager.CurrentTransaction.Rollback(). Per ulteriori informazioni, vedere Gestori di modifica del valore delle proprietà del dominio.

Nota di avvisoAttenzione

Assicurarsi che l'utente sappia che la modifica è stata modificata o rotolato stata indietro.Ad esempio, utilizzare System.Windows.Forms.MessageBox.Show("message").

Vedere anche

Concetti

Esplorazione e aggiornamento di un modello nel codice del programma

I gestori eventi propagano le modifiche al di fuori del modello