Partager via


Propagation de modifications en dehors du modèle par des gestionnaires d'événements

Dans le SDK Visualization and Modeling, vous pouvez définir des gestionnaires d’événements de magasin pour propager les modifications apportées aux ressources en dehors du magasin, comme les variables, les fichiers, les modèles dans d’autres magasins ou d’autres extensions Visual Studio. Les gestionnaires d’événements de magasin sont exécutés après la fin de la transaction dans laquelle l’événement déclencheur s’est produit. Ils sont également exécutés dans une opération Annuler ou Rétablir. Par conséquent, contrairement aux règles de magasin, les événements de magasin sont plus utiles pour mettre à jour des valeurs qui se trouvent en dehors du magasin. Contrairement aux événements .NET, les gestionnaires d’événements de magasin sont inscrits pour écouter une classe : vous n’avez pas besoin d’inscrire un gestionnaire distinct pour chaque instance. Pour plus d’informations sur la façon de choisir entre différentes façons de gérer les modifications, consultez Propagation et réponse aux modifications.

La surface graphique et les autres contrôles d’interface utilisateur sont des exemples de ressources externes qui peuvent être gérées par des événements de magasin.

Pour définir un événement de magasin

  1. Choisissez le type d’événement que vous souhaitez surveiller. Pour obtenir la liste complète, examinez les propriétés de EventManagerDirectory. Chaque propriété correspond à un type d’événement. Les types d’événements les plus fréquemment utilisés sont les suivants :

    • ElementAdded - déclenché lors de la création d’un élément de modèle, d’un lien de relation, d’une forme ou d’un connecteur.

    • ElementPropertyChanged : déclenché lorsque la valeur d’une propriété de domaine Normal est modifiée. L’événement est déclenché uniquement si les valeurs nouvelles et anciennes ne sont pas égales. L’événement ne peut pas être appliqué aux propriétés de stockage calculées et personnalisées.

      Il ne peut pas être appliqué aux propriétés de rôle qui correspondent aux liaisons de relation. Utilisez plutôt ElementAdded pour surveiller la relation de domaine.

    • ElementDeleted - déclenché après la suppression d’un élément de modèle, d’une relation, d’une forme ou d’un connecteur. Vous pouvez toujours accéder aux valeurs de propriété de l’élément, mais il n’aura aucune relation avec les autres éléments.

  2. Ajoutez une définition de classe partielle pour YourDslDocData dans un fichier de code distinct dans le projet DslPackage.

  3. Écrivez le code de l’événement en tant que méthode, comme dans l’exemple suivant. Il peut s’agir de static, sauf si vous souhaitez accéder à DocData.

  4. Remplacez OnDocumentLoaded() pour inscrire le descripteur. Si vous avez plusieurs gestionnaires, vous pouvez les inscrire tous au même emplacement.

L’emplacement du code d’inscription n’est pas critique. DocView.LoadView() est un autre emplacement.

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

namespace Company.MusicLib
{
  partial class MusicLibDocData
  {
    // Register store events here or in DocView.LoadView().
    protected override void OnDocumentLoaded()
    {
      base.OnDocumentLoaded(); // Don't forget this.

      #region Store event handler registration.
      Store store = this.Store;
      EventManagerDirectory emd = store.EventManagerDirectory;
      DomainRelationshipInfo linkInfo = store.DomainDataDirectory
          .FindDomainRelationship(typeof(ArtistAppearsInAlbum));
      emd.ElementAdded.Add(linkInfo,
          new EventHandler<ElementAddedEventArgs>(AddLink));
      emd.ElementDeleted.Add(linkInfo,
          new EventHandler<ElementDeletedEventArgs>(RemoveLink));

      #endregion Store event handlers.
    }

    private void AddLink(object sender, ElementAddedEventArgs e)
    {
      ArtistAppearsInAlbum link = e.ModelElement as ArtistAppearsInAlbum;
      if (link != null)
            ExternalDatabase.Add(link.Artist.Name, link.Album.Title);
    }
    private void RemoveLink(object sender, ElementDeletedEventArgs e)
    {
      ArtistAppearsInAlbum link = e.ModelElement as ArtistAppearsInAlbum;
      if (link != null)
            ExternalDatabase.Delete(link.Artist.Name, link.Album.Title);
    }
  }
}

Utiliser des événements pour effectuer des ajustements non modifiables dans le magasin

Les événements de magasin ne sont normalement pas utilisés pour propager les modifications à l’intérieur du magasin, car le gestionnaire d’événements s’exécute après la validation de la transaction. Au lieu de cela, vous utiliseriez une règle de magasin. Pour plus d’informations, consultez Propagation de modifications dans le modèle par des règles.

Toutefois, vous pouvez utiliser un gestionnaire d’événements pour apporter des mises à jour supplémentaires au magasin, si vous souhaitez que l’utilisateur puisse annuler les mises à jour supplémentaires séparément de l’événement d’origine. Par exemple, supposons que les caractères minuscules constituent la convention habituelle pour les titres d’album. Vous pouvez écrire un gestionnaire d’événements de magasin qui corrige le titre en minuscules une fois que l’utilisateur l’a tapé en majuscules. Mais l’utilisateur peut utiliser la commande Annuler pour annuler votre correction, restaurant ainsi les caractères majuscules. Une deuxième annulation supprimerait la modification de l’utilisateur.

En revanche, si vous avez écrit une règle de magasin pour faire la même chose, la modification de l’utilisateur et votre correction se trouveraient dans la même transaction, de sorte que l’utilisateur ne pourrait pas annuler l’ajustement sans perdre la modification d’origine.

partial class MusicLibDocView
{
    // Register store events here or in DocData.OnDocumentLoaded().
    protected override void LoadView()
    {
      /* Register store event handler for Album Title property. */
      // Get reflection data for property:
      DomainPropertyInfo propertyInfo =
        this.DocData.Store.DomainDataDirectory
        .FindDomainProperty(Album.TitleDomainPropertyId);
      // Add to property handler list:
      this.DocData.Store.EventManagerDirectory
        .ElementPropertyChanged.Add(propertyInfo,
        new EventHandler<ElementPropertyChangedEventArgs>
             (AlbumTitleAdjuster));

      /*
      // Alternatively, you can set one handler for
      // all properties of a class.
      // Your handler has to determine which property changed.
      DomainClassInfo classInfo = this.Store.DomainDataDirectory
           .FindDomainClass(typeof(Album));
      this.Store.EventManagerDirectory
          .ElementPropertyChanged.Add(classInfo,
        new EventHandler<ElementPropertyChangedEventArgs>
             (AlbumTitleAdjuster));
       */
      return base.LoadView();
    }

// Undoable adjustment after a property is changed.
// Method can be static since no local access.
private static void AlbumTitleAdjuster(object sender,
         ElementPropertyChangedEventArgs e)
{
  Album album = e.ModelElement as Album;
  Store store = album.Store;

  // We mustn't update the store in an Undo:
  if (store.InUndoRedoOrRollback
      || store.InSerializationTransaction)
      return;

  if (e.DomainProperty.Id == Album.TitleDomainPropertyId)
  {
    string newValue = (string)e.NewValue;
    string lowerCase = newValue.ToLowerInvariant();
    if (!newValue.Equals(lowerCase))
    {
      using (Transaction t = store.TransactionManager
            .BeginTransaction("adjust album title"))
      {
        album.Title = lowerCase;
        t.Commit();
      } // Beware! This could trigger the event again.
    }
  }
  // else other properties of this class.
}

Si vous écrivez un événement qui met à jour le magasin :

  • Utilisez store.InUndoRedoOrRollback pour éviter d’apporter des modifications aux éléments de modèle dans Annuler. Le gestionnaire de transactions rétablit l’état d’origine de tout ce qui se trouve dans le magasin.

  • Utilisez store.InSerializationTransaction pour éviter d’apporter des modifications pendant le chargement du modèle à partir du fichier.

  • Vos modifications entraîneront le déclenchement d’autres événements. Veillez à éviter une boucle infinie.

Types d’événements de magasin

Chaque type d’événement correspond à une collection dans Store.EventManagerDirectory. Vous pouvez ajouter ou supprimer des gestionnaires d’événements à tout moment, mais il est habituel de les ajouter lorsque le document est chargé.

EventManagerDirectory Nom de la propriété Exécuté lors de l’exécution
ElementAdded Une instance d’une classe de domaine, d’une relation de domaine, d’une forme, d’un connecteur ou d’un diagramme est créée.
ElementDeleted Un élément de modèle a été supprimé du répertoire d’éléments du magasin et n’est plus la source ou la cible d’une relation. L’élément n’est pas réellement supprimé de la mémoire ; il est conservé en cas d’annulation ultérieure.
ElementEventsBegun Appelé à la fin d’une transaction externe.
ElementEventsEnded Appelé lorsque tous les autres événements ont été traités.
ElementMoved Un élément de modèle a été déplacé d’une partition de magasin vers une autre.

Cela n’est pas lié à l’emplacement d’une forme sur le diagramme.
ElementPropertyChanged La valeur d’une propriété de domaine a changé. Cette opération n’est exécutée que si l’ancienne et la nouvelle valeur sont différentes.
RolePlayerChanged L’un des deux rôles (extrémités) d’une relation fait référence à un nouvel élément.
RolePlayerOrderChanged Dans un rôle dont la multiplicité est supérieure à 1, la séquence de liens a changé.
TransactionBeginning
TransactionCommitted
TransactionRolledBack

Notes

Le composant Transformation de modèle de texte est automatiquement installé dans le cadre de la charge de travail Développement d’extensions Visual Studio. Vous pouvez aussi l’installer à partir de l’onglet Composants individuels de Visual Studio Installer, sous la catégorie SDK, bibliothèques et frameworks. Installez le composant Modeling SDK à partir de l’onglet Composants individuels.