Delen via


Regels verspreiden wijzigingen binnen het model

U kunt een store-regel maken om een wijziging van het ene element naar het andere te propageren in Visualisatie en Modellering SDK (VMSDK). Wanneer er een wijziging plaatsvindt in een element in de Store, worden regels ingepland om te worden uitgevoerd, meestal wanneer de buitenste transactie wordt bevestigd. Er zijn verschillende soorten regels voor verschillende soorten gebeurtenissen, zoals het toevoegen van een element of het verwijderen ervan. U kunt regels koppelen aan specifieke typen elementen, vormen of diagrammen. Veel ingebouwde functies worden gedefinieerd door regels: regels zorgen er bijvoorbeeld voor dat een diagram wordt bijgewerkt wanneer het model wordt gewijzigd. U kunt uw domeinspecifieke taal aanpassen door uw eigen regels toe te voegen.

Opslagregels zijn met name handig voor het doorgeven van wijzigingen in de opslag: wijzigingen in modelelementen, relaties, vormen of verbindingen en hun domeineigenschappen. Regels worden niet uitgevoerd wanneer de gebruiker de opdrachten Ongedaan maken of Opnieuw aanroept. In plaats daarvan zorgt de transactiebeheerder ervoor dat de inhoud van het archief wordt hersteld naar de juiste status. Als u wijzigingen wilt doorgeven aan resources buiten de store, gebruikt u Store-gebeurtenissen. Voor meer informatie, zie Gebeurtenishandlers geven wijzigingen buiten het model door.

Stel dat u wilt opgeven dat wanneer de gebruiker (of uw code) een nieuw element van het type ExampleDomainClass maakt, een extra element van een ander type wordt gemaakt in een ander deel van het model. U kunt een AddRule schrijven en deze koppelen aan ExampleDomainClass. U schrijft code in de regel om het extra element te maken.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;

namespace ExampleNamespace
{
 // Attribute associates the rule with a domain class:
 [RuleOn(typeof(ExampleDomainClass), FireTime=TimeToFire.TopLevelCommit)]
 // The rule is a class derived from one of the abstract rules:
 class MyAddRule : AddRule
 {
  // Override the abstract method:
  public override void ElementAdded(ElementAddedEventArgs e)
  {
    base.ElementAdded(e);
    ExampleDomainClass element = e.ModelElement;
    Store store = element.Store;
    // Ignore this call if we're currently loading a model:
    if (store.TransactionManager.CurrentTransaction.IsSerializing)
       return;

    // Code here propagates change as required - for example:
      AnotherDomainClass echo = new AnotherDomainClass(element.Partition);
      echo.Name = element.Name;
      echo.Parent = element.Parent;
    }
  }
 // The rule must be registered:
 public partial class ExampleDomainModel
 {
   protected override Type[] GetCustomDomainModelTypes()
   {
     List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
     types.Add(typeof(MyAddRule));
     // If you add more rules, list them here.
     return types.ToArray();
   }
 }
}

Opmerking

De code van een regel moet alleen de status van elementen in de Store wijzigen; Dat wil gezegd, de regel mag alleen modelelementen, relaties, shapes, verbindingslijnen, diagrammen of hun eigenschappen wijzigen. Als u wijzigingen wilt doorgeven aan resources buiten de store, definieert u Store-gebeurtenissen. Voor meer informatie, zie Gebeurtenishandlers geven wijzigingen buiten het model door.

Een regel definiëren

  1. Definieer de regel als een klasse die wordt voorafgegaan door het RuleOn attribuut. Het kenmerk koppelt de regel aan een van uw domeinklassen, relaties of diagramelementen. De regel wordt toegepast op elk exemplaar van deze klasse, wat abstract kan zijn.

  2. Registreer de regel door deze toe te voegen aan de set die door GetCustomDomainModelTypes() in uw domeinmodelklasse wordt geretourneerd.

  3. De regelklasse afleiden van een van de abstracte regelklassen en de code van de uitvoeringsmethode schrijven.

    In de volgende secties worden deze stappen gedetailleerder beschreven.

Een regel definiëren voor een domeinklasse

  • Definieer in een aangepast codebestand een klasse en voorvoegsel met het RuleOnAttribute kenmerk:

    [RuleOn(typeof(ExampleElement),
         // Usual value - but required, because it is not the default:
         FireTime = TimeToFire.TopLevelCommit)]
    class MyRule ...
    
    
  • Het onderwerptype in de eerste parameter kan een domeinklasse, domeinrelatie, shape, connector of diagram zijn. Normaal gesproken past u regels toe op domeinklassen en -relaties.

    De FireTime is meestal TopLevelCommit. Dit zorgt ervoor dat de regel pas wordt uitgevoerd nadat alle primaire wijzigingen van de transactie zijn aangebracht. De alternatieven zijn Inline, waarmee de regel kort na de wijziging wordt uitgevoerd; en LocalCommit, waarmee de regel aan het einde van de huidige transactie wordt uitgevoerd (wat mogelijk niet de buitenste transactie is). U kunt ook de prioriteit van een regel instellen om de volgorde ervan in de wachtrij te beïnvloeden, maar dit is een onbetrouwbare methode om het gewenste resultaat te bereiken.

  • U kunt een abstracte klasse opgeven als onderwerptype.

  • De regel is van toepassing op alle exemplaren van de subjectklasse.

  • De standaardwaarde voor FireTime is TimeToFire.TopLevelCommit. Dit zorgt ervoor dat de regel wordt uitgevoerd wanneer de buitenste transactie wordt doorgevoerd. Een alternatief is TimeToFire.Inline. Hierdoor wordt de regel kort na de triggergebeurtenis uitgevoerd.

Om de regel te registreren

  • Voeg uw regelklasse toe aan de lijst met typen die in GetCustomDomainModelTypes uw domeinmodel worden geretourneerd:

    public partial class ExampleDomainModel
     {
       protected override Type[] GetCustomDomainModelTypes()
       {
         List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
         types.Add(typeof(MyAddRule));
         // If you add more rules, list them here.
         return types.ToArray();
       }
     }
    
    
  • Als u niet zeker weet wat de naam van uw domeinmodelklasse is, kijkt u in het bestand Dsl\GeneratedCode\DomainModel.cs

  • Schrijf deze code in een aangepast codebestand in uw DSL-project.

De regelcode schrijven

  • De regelklasse afleiden van een van de volgende basisklassen:

    Basisklasse Aanleiding
    AddRule Er wordt een element, koppeling of vorm toegevoegd.

    Gebruik deze optie om nieuwe relaties te detecteren, naast nieuwe elementen.
    ChangeRule De waarde van een domeineigenschap wordt gewijzigd. Het methodeargument bevat de oude en nieuwe waarden.

    Voor shapes wordt deze regel geactiveerd wanneer de ingebouwde AbsoluteBounds eigenschap wordt gewijzigd, als de shape wordt verplaatst.

    In veel gevallen is het handiger om te overschrijven OnValueChanged of OnValueChanging in de eigenschapshandler. Deze methoden worden onmiddellijk voor en na de wijziging aangeroepen. De regel wordt daarentegen meestal uitgevoerd aan het einde van de transactie. Zie Handlers voor het wijzigen van domeineigenschapswaarden voor meer informatie. Notitie: Deze regel wordt niet geactiveerd wanneer een koppeling wordt gemaakt of verwijderd. Schrijf in plaats daarvan een AddRule en een DeleteRule voor de domeinrelatie.
    DeletingRule Geactiveerd wanneer een element of koppeling op het punt staat te worden verwijderd. De eigenschap ModelElement.IsDeleting is waar tot het einde van de transactie.
    DeleteRule Uitgevoerd wanneer een element of koppeling is verwijderd. De regel wordt uitgevoerd nadat alle andere regels zijn uitgevoerd, inclusief DeletingRules. ModelElement.IsDeleting is onwaar en ModelElement.IsDeleted is waar. Als u een volgende ongedaan maken wilt toestaan, wordt het element niet daadwerkelijk uit het geheugen verwijderd, maar wordt het verwijderd uit Store.ElementDirectory.
    MoveRule Een element wordt verplaatst van de ene archiefpartitie naar de andere.

    (U ziet dat dit niet gerelateerd is aan de grafische positie van een shape.)
    RolePlayerChangeRule Deze regel is alleen van toepassing op domeinrelaties. Deze wordt geactiveerd als u expliciet een modelelement toewijst aan een van beide uiteinden van een koppeling.
    RolePlayerPositionChangeRule Geactiveerd wanneer de volgorde van koppelingen naar of van een element wordt gewijzigd met behulp van de methoden MoveBefore of MoveToIndex op een koppeling.
    TransactionBeginningRule Wordt uitgevoerd wanneer een transactie wordt gemaakt.
    TransactionCommittingRule Wordt uitgevoerd wanneer de transactie op het punt staat te worden doorgevoerd.
    TransactionRollingBackRule Wordt uitgevoerd wanneer de transactie op het punt staat terug te draaien.
  • Elke klasse heeft een methode die u overschrijft. Typ override in uw klasse om het te ontdekken. De parameter van deze methode identificeert het element dat wordt gewijzigd.

    Let op de volgende punten over regels:

  1. De set wijzigingen in een transactie kan veel regels activeren. Normaal gesproken worden de regels uitgevoerd wanneer de buitenste transactie wordt doorgevoerd. Ze worden uitgevoerd in een niet-opgegeven volgorde.

  2. Een regel wordt altijd uitgevoerd binnen een transactie. Daarom hoeft u geen nieuwe transactie te maken om wijzigingen aan te brengen.

  3. Regels worden niet uitgevoerd wanneer een transactie wordt geannuleerd of wanneer de bewerkingen Ongedaan maken of Opnieuw uitvoeren worden uitgevoerd. Met deze bewerkingen wordt alle inhoud van de Store opnieuw ingesteld op de vorige status. Als uw regel de status van iets buiten de Store wijzigt, blijft deze mogelijk niet synchroon met de Store-inhoud. Als u de status buiten de Store wilt bijwerken, is het beter om gebeurtenissen te gebruiken. Voor meer informatie, zie Gebeurtenishandlers geven wijzigingen buiten het model door.

  4. Sommige regels worden uitgevoerd wanneer een model uit het bestand wordt geladen. Als u wilt bepalen of het laden of opslaan wordt uitgevoerd, gebruikt u store.TransactionManager.CurrentTransaction.IsSerializing.

  5. Als de code van uw regel meer regeltriggers maakt, worden ze toegevoegd aan het einde van de lijst met activeringen en worden ze uitgevoerd voordat de transactie is voltooid. DeletedRules worden toegepast na alle andere regels. Eén regel kan meerdere keren in een transactie worden uitgevoerd, één keer voor elke wijziging.

  6. Als u gegevens wilt uitwisselen tussen regels, kunt u informatie opslaan in de TransactionContext. Dit is slechts een woordenlijst die tijdens de transactie wordt onderhouden. Deze wordt verwijderd wanneer de transactie eindigt. De gebeurtenisargumenten in elke regel bieden toegang tot deze regel. Houd er rekening mee dat regels niet in een voorspelbare volgorde worden uitgevoerd.

  7. Gebruik regels na het overwegen van andere alternatieven. Als u bijvoorbeeld een eigenschap wilt bijwerken wanneer een waarde verandert, kunt u overwegen een berekende eigenschap te gebruiken. Als u de grootte of locatie van een shape wilt beperken, gebruikt u een BoundsRule. Als u wilt reageren op een wijziging in een eigenschapswaarde, voegt u een OnValueChanged handler toe aan de eigenschap. Zie Reageren op en doorgeven van wijzigingen voor meer informatie.

Example

In het volgende voorbeeld wordt een eigenschap bijgewerkt wanneer een domeinrelatie wordt geïnstantieerd om twee elementen te koppelen. De regel wordt niet alleen geactiveerd wanneer de gebruiker een koppeling in een diagram maakt, maar ook als programmacode een koppeling maakt.

Als u dit voorbeeld wilt testen, maakt u een DSL met behulp van de taakstroomoplossingssjabloon en voegt u de volgende code in een bestand in het Dsl-project in. Bouw en voer de oplossing uit en open het voorbeeldbestand in het project Foutopsporing. Teken een opmerkingenlink tussen een opmerkingenvorm en een stroomelement. De tekst in de opmerking wordt aangepast om te rapporteren over het nieuwste element waarmee u het heeft verbonden.

In de praktijk schrijft u meestal een DeleteRule voor elke AddRule.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;

namespace Company.TaskRuleExample
{

  [RuleOn(typeof(CommentReferencesSubjects))]
  public class RoleRule : AddRule
  {

    public override void ElementAdded(ElementAddedEventArgs e)
    {
      base.ElementAdded(e);
      CommentReferencesSubjects link = e.ModelElement as CommentReferencesSubjects;
      Comment comment = link.Comment;
      FlowElement subject = link.Subject;
      Transaction current = link.Store.TransactionManager.CurrentTransaction;
      // Don't want to run when we're just loading from file:
      if (current.IsSerializing) return;
      comment.Text = "Flow has " + subject.FlowTo.Count + " outgoing connections";
    }

  }

  public partial class TaskRuleExampleDomainModel
  {
    protected override Type[] GetCustomDomainModelTypes()
    {
      List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
      types.Add(typeof(RoleRule));
      return types.ToArray();
    }
  }

}