Partager via


Navigation et mise à jour d'un modèle dans le code de programme

Vous pouvez écrire du code pour créer et supprimer des éléments de modèle, définir leurs propriétés, et de créer et supprimer des liens entre des éléments. toutes les modifications doivent être apportées dans une transaction. si les éléments sont affichés sur un diagramme, le diagramme « sera résolu » automatiquement à la fin de la transaction.

Dans cette rubrique

Une définition de l'exemple DÉSOLÉ

Naviguer dans le modèle

Les informations de classe de accès

Exécuter des modifications dans une transaction

créer des éléments de modèle

Créer la relation Liens

supprimer des éléments

Supprimer la relation Liens

Réorganisation de Liens d'une relation

verrous

Copier et coller

Accès au modèle et mise à jour des diagrammes

naviguer entre les formes et les éléments

Propriétés de formes et de connecteurs

DocView et DocData

Des formes, les connecteurs et les diagrammes, et leurs relations aux éléments de modèle sont décrits dans une rubrique séparée. Pour plus d'informations, consultez [redirection] Comment : mettre à jour et naviguer dans un schéma.

Une définition de l'exemple DÉSOLÉ

Il s'agit de la majeure partie de DslDefinition.dsl pour les exemples de cette rubrique :

Diagramme de définition DSL - modèle d'arbre généalogique

Ce modèle est une instance de ce langage DÉSOLÉ :

Modèle d'arbre généalogique de la famille Tudor

Références et des espaces de noms

Pour exécuter du code dans cette rubrique, vous devez référencer :

Microsoft.VisualStudio.Modeling.Sdk.11.0.dll

Votre code utilise cet espace de noms :

using Microsoft.VisualStudio.Modeling;

En outre, si vous écrivez du code dans un projet différent de celui dans lequel votre DÉSOLÉ est défini, vous devez importer l'assembly généré par le projet DÉSOLÉ.

Propriétés

Les propriétés de domaine que vous définissez dans la définition DÉSOLÉ deviennent des propriétés auxquelles vous pouvez accéder dans le code du programme :

Person henry = ...;

if (henry.BirthDate < 1500) ...

if (henry.Name.EndsWith("VIII")) ...

Si vous souhaitez définir une propriété, vous devez le faire à l'intérieur de transaction:

henry.Name = "Henry VIII";

Si dans la définition DÉSOLÉ, type d'une propriété est calculé, vous ne pouvez pas la définir. Pour plus d'informations, consultez Propriétés de stockage calculées et personnalisées.

Relations

Les relations de domaine que vous définissez dans la définition DÉSOLÉ deviennent des paires de propriétés, d'une sur la classe à chaque extrémité de la relation. Les noms des propriétés s'affichent dans le diagramme de DslDefinition en tant que noms sur les rôles sur chaque côté de la relation. Selon la multiplicité du rôle, le type de la propriété est la classe à l'autre extrémité de la relation, ou une collection de cette classe.

foreach (Person child in henry.Children) { ... }

FamilyTreeModel ftree = henry.FamilyTreeModel;

Les propriétés aux extrêmes inverses d'une relation sont toujours réciproque. Lorsqu'un lien est créé ou supprimé, le rôle de propriétés sur les deux éléments sont mis à jour. L'expression suivante (qui utilise les extensions d' System.Linq) est toujours true pour la relation de ParentsHaveChildren dans l'exemple :

(Person p) => p.Children.All(child => child.Parents.Contains(p))

&& p.Parents.All(parent => parent.Children.Contains(p));

ElementLinks. une relation est également représentée par un élément de modèle appelé un lien, qui est une instance du type de relation de domaine. un lien a toujours un élément source et un élément cible. l'élément source et l'élément cible peuvent être identique.

vous pouvez accéder à un lien et à ses propriétés :

ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);

// This is now true:

link == null || link.Parent == henry && link.Child == edward

Par défaut, il n'autorise qu'une seule instance d'une relation pour lier une paire d'éléments de modèle. Mais si dans la définition DÉSOLÉ, la balise d' Allow Duplicates est vrai pour la relation, il peut exister plusieurs liens, et vous devez utiliser GetLinks:

foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }

Il existe d'autres méthodes pour accéder aux liens. Par exemple :

foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }

rôles masqués. Si dans la définition DÉSOLÉ, est la propriété générée est false pour un rôle particulier, aucune propriété n'est générée qui correspond à ce rôle. Toutefois, vous pouvez accéder aux liens et toujours parcourir les liens à l'aide de les méthodes de relation :

foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }

Le plus souvent l'exemple utilisé est la relation d' PresentationViewsSubject , qui lie un élément de modèle vers la forme qui l'affiche dans un diagramme :

PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape

Le répertoire d'élément

Vous pouvez accéder à tous les éléments dans le magasin dans le répertoire d'élément :

store.ElementDirectory.AllElements

Il existe également des méthodes pour rechercher des éléments, tels que :

store.ElementDirectory.FindElements(Person.DomainClassId);

store.ElementDirectory.GetElement(elementId);

Les informations de classe de accès

Vous pouvez obtenir des informations sur les classes, les relations, et d'autres aspects de la définition de langage spécifique à un domaine. Par exemple :

DomainClassInfo personClass = henry.GetDomainClass();

DomainPropertyInfo birthProperty =

personClass.FindDomainProperty("BirthDate")

DomainRelationshipInfo relationship =

link.GetDomainRelationship();

DomainRoleInfo sourceRole = relationship.DomainRole[0];

Les classes ancêtres des éléments de modèle sont les suivantes :

  • ModelElement - tous les éléments et des relations sont ModelElements

  • ElementLink - toutes les relations sont ElementLinks

Exécuter des modifications dans une transaction

Chaque fois que votre code de programme modifie une valeur dans le magasin, il doit le faire dans une transaction. Cela s'applique à tous les éléments de modèle, des relations, à formes, à diagrammes, et à leurs propriétés. Pour plus d'informations, consultez Transaction.

La méthode la plus pratique de gérer une transaction consiste à utiliser une instruction d' using comprise dans une instruction d' try...catch :

Store store; ...
try
{
  using (Transaction transaction =
    store.TransactionManager.BeginTransaction("update model"))
    // Outermost transaction must always have a name.
  {
    // Make several changes in Store:
    Person p = new Person(store);
    p.FamilyTreeModel = familyTree;
    p.Name = "Edward VI";
    // end of changes to Store

    transaction.Commit(); // Don't forget this!
  } // transaction disposed here
}
catch (Exception ex)
{
  // If an exception occurs, the Store will be 
  // rolled back to its previous state.
}

Vous pouvez apporter plusieurs modifications dans une transaction. Vous pouvez ouvrir de nouveaux transactions dans une transaction active.

Pour que votre constante de modifications, vous devez Commit la transaction avant qu'elle soit supprimée. Si une exception n'est pas interceptée dans la transaction, le magasin sera réinitialisée à son état avant que les modifications.

créer des éléments de modèle

cet exemple ajoute un élément à un modèle existant :

FamilyTreeModel familyTree = ...; // The root of the model.       
using (Transaction t =
    familyTree.Store.TransactionManager
    .BeginTransaction("update model"))
{
  // Create a new model element 
  // in the same partition as the model root:
  Person edward = new Person(familyTree.Partition);
  // Set its embedding relationship:
  edward.FamilyTreeModel = familyTree;
          // same as: familyTree.People.Add(edward);
  // Set its properties:
  edward.Name = "Edward VII";
  t.Commit(); // Don't forget this!
}

Cet exemple illustre ces points essentiels liés au créer un élément :

  • Créez l'élément dans une partition spécifique de le magasin. Pour les éléments de modèle et les relations, mais pas des formes, cela est généralement la partition par défaut.

  • Faites -en la cible d'une relation d'incorporation. dans le DslDefinition de cet exemple, chaque personne doit être la cible de la relation FamilyTreeHasPeople d'incorporation. Pour ce faire, nous pouvons ou définir le rôle de propriété de FamilyTreeModel de l'objet de personne, ou ajouter la personne aux personnes de rôle de la propriété de l'objet de FamilyTreeModel.

  • Définissez les propriétés d'un nouvel élément, en particulier la propriété pour lequel IsName a la valeur true dans le DslDefinition. Cette balise marque la propriété qui sert à identifier l'élément uniquement dans son propriétaire. dans ce cas, la propriété Name a cette balise.

  • La définition DÉSOLÉ de ce langage DÉSOLÉ doit avoir été chargée dans le magasin. Si vous écrivez une extension telle qu'une commande de menu, il s'agira généralement déjà remplie. Dans d'autres cas, vous pouvez explicitement charger le modèle dans le magasin, ou utilisez ModelBus pour le charger. Pour plus d'informations, consultez Comment : ouvrir un modèle depuis un fichier dans le code de programme.

Lorsque vous créez un élément de cette façon, une forme est automatiquement créé (si le DÉSOLÉ est un schéma). Elle apparaît dans un emplacement automatiquement assigné, avec la forme par défaut, la couleur, et autres fonctionnalités. Si vous souhaitez contrôler l'emplacement et comment la forme associée apparaît, consultez créer un élément et sa forme.

Créer la relation Liens

Il existe deux relations définies dans la définition de l'exemple DÉSOLÉ. Chaque relation définit un rôle de la propriété sur la classe à chaque extrémité de la relation.

Il existe trois façons dont vous pouvez créer une instance d'une relation. chacune de ces trois méthodes a le même effet :

  • Affectez à la propriété du rôle lecteur de source. Par exemple :

    • familyTree.People.Add(edward);

    • edward.Parents.Add(henry);

  • Affectez à la propriété du rôle lecteur cible. Par exemple :

    • edward.familyTreeModel = familyTree;

      La multiplicité de ce rôle est 1..1, nous assignons la valeur.

    • henry.Children.Add(edward);

      La multiplicité de ce rôle est 0..*, nous ajoutons à la collection.

  • Construit une instance de la relation explicitement. Par exemple :

    • FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);

    • ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);

La dernière méthode est utile lorsque vous souhaitez définir les propriétés de la relation elle-même.

Lorsque vous créez un élément de cette façon, un connecteur sur le diagramme est automatiquement créé, mais il a une forme, une couleur, et une autre par défaut des fonctionnalités. Pour contrôler la façon dont le connecteur associé est créé, consultez créer un élément et sa forme.

supprimer des éléments

supprimez un élément en appelant Delete():

henry.Delete();

Cette opération supprime également :

  • Liens de relation vers et depuis l'élément. par exemple, edward.Parents ne contiendra plus henry.

  • Éléments aux rôles pour lesquels la balise d' PropagatesDelete a la valeur true. par exemple, la forme qui affiche l'élément sera supprimée.

Par défaut, chaque relation d'incorporer un PropagatesDelete vrai au rôle cible. Suppression henry ne supprime pas familyTree, mais familyTree.Delete() supprimerait tous les Persons. Pour plus d'informations, consultez Personnalisation du comportement de la commande de suppression.

par défaut, PropagatesDelete n'est pas vrai pour les rôles des relations de référence.

Vous pouvez provoquer des règles de suppression d'omettre des propagations spécifiques lorsque vous supprimez un objet. Cela est utile si vous substituez un élément pour les autres. Vous fournissez le GUID d'un ou plusieurs rôles pour lesquels la suppression ne doit pas être propagée. GUID peut être obtenu à partir de la classe de relation :

henry.Delete(ParentsHaveChildren.SourceDomainRoleId);

(Cet exemple particulier n'aurait aucun effet, car PropagatesDelete est false pour les rôles de la relation d' ParentsHaveChildren .)

Dans certains cas, la suppression est bloquée par l'existence d'un verrou, dans l'élément ou un élément qui serait ignoré par propagation. Vous pouvez utiliser element.CanDelete() pour vérifier si l'élément peut être supprimé.

Supprimer la relation Liens

vous pouvez supprimer un lien de relation en supprimant un élément d'un rôle de propriété :

henry.Children.Remove(edward); // or:

edward.Parents.Remove(henry); // or:

vous pouvez également supprimer le lien explicitement :

edwardHenryLink.Delete();

Ces trois méthodes ont toutes le même effet. Vous devez utiliser uniquement l'un d'eux.

Si le rôle possède 0..1 ou 1..1 multiplicité, vous pouvez lui affecter à null, ou une autre valeur :

edward.FamilyTreeModel = null; //ou :

edward.FamilyTreeModel = anotherFamilyTree;

Retrier les liens d'une relation

Les liens d'une relation particulière qui sont générés ou ciblés à un élément de modèle particulier ont un ordre spécifique. Ils apparaissent dans l'ordre dans lequel ils ont été ajoutés. Par exemple, cette instruction génère toujours les enfants dans la même commande :

foreach (Person child in henry.Children) ...

Vous pouvez modifier l'ordre des liens :

ParentsHaveChildren link = GetLink(henry,edward);

ParentsHaveChildren nextLink = GetLink(henry, elizabeth);

DomainRoleInfo role =

link.GetDomainRelationship().DomainRoles[0];

link.MoveBefore(role, nextLink);

verrous

Vos modifications peuvent être empêchées par un verrou. Les verrous peuvent être définis sur différents éléments, sur les partitions, et dans le magasin. Si l'un de ces niveaux possède un verrou qui empêché le type de modification que vous souhaitez faire, une exception peut être levée lorsque vous tentez la. Vous pouvez déterminer si les verrous sont définis à l'aide de l'élément. GetLocks(), qui est une méthode d'extension qui est définie dans Immutability.

Pour plus d'informations, consultez Définition d'une stratégie de verrouillage pour créer des segments en lecture seule.

Copier et coller

vous pouvez copier des éléments ou des groupes d'éléments à IDataObject:

Person person = personShape.ModelElement as Person;
Person adopter = adopterShape.ModelElement as Person;
IDataObject data = new DataObject();
personShape.Diagram.ElementOperations
      .Copy(data, person.Children.ToList<ModelElement>());

Les éléments sont stockés en tant que groupe sérialisé d'élément.

vous pouvez fusionner des éléments d'un IDataObject dans un modèle :

using (Transaction t = targetDiagram.Store.
        TransactionManager.BeginTransaction("paste"))
{
  adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}

Merge () peut recevoir PresentationElement ou ModelElement. Si vous lui donnez PresentationElement, vous pouvez également spécifier une position dans le schéma cible comme troisième paramètre.

Accès au modèle et mise à jour des diagrammes

Dans un langage spécifique à un domaine, l'élément de modèle de domaine, qui représente un concept tel que la personne ou la chanson, est distinct de l'élément de forme, qui représente ce que vous voyez dans le diagramme. l'élément de modèle de domaine enregistre les propriétés et les relations importantes des concepts. L'élément de forme enregistre la taille, la position et couleur de la vue de l'objet sur le diagramme, et la disposition de ses éléments.

éléments de présentation

Diagramme de classes de la forme de base et des types d'éléments

Dans la définition de votre DÉSOLÉ, chaque élément que vous spécifiez crée une classe dérivée d'une des classes standard suivantes.

Type d'élément

Classe de base

classe de domaine

ModelElement

relation de domaine

ElementLink

Forme

NodeShape

connecteur

BinaryLinkShape

Schéma

Diagram

un élément sur un diagramme représente habituellement un élément de modèle. Généralement (mais pas toujours), NodeShape représente une instance de la classe de domaine, et BinaryLinkShape représente une instance de relation de domaine. La relation d' PresentationViewsSubject lie une forme de nœuds ou de liens à l'élément de modèle qu'elle représente.

Chaque forme de nœuds ou de liens appartient à un diagramme. Une forme binaire de lien connecte deux formes de nœud.

Les formes peuvent avoir des formes enfants dans deux jeux. Une forme de NestedChildShapes défini est confinée à la zone englobante de son parent. Une forme de la liste d' RelativeChildShapes peut apparaître à l'extérieur de ou en partie à l'extérieur de les limites du parent (par exemple un nom ou un port. un diagramme n'a aucun RelativeChildShapes et aucun Parent.

Les éléments du modèle de domaine et les éléments de forme sont mis en relation par la relation d' PresentationViewsSubject .

// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape = 
  PresentationViewsSubject.GetPresentation(henry)
    .FirstOrDefault() as PersonShape;

La même relation lie les relations aux connecteurs sur le diagramme :

Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
   PresentationViewsSubject.GetPresentation(link)
     .FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape

Cette relation fournit également la racine du modèle au diagramme :

FamilyTreeDiagram diagram = 
   PresentationViewsSubject.GetPresentation(familyTree)
      .FirstOrDefault() as FamilyTreeDiagram;

Pour obtenir l'élément de modèle représenté par une forme, utilisez :

henryShape.ModelElement as Person

diagram.ModelElement as FamilyTreeModel

en général il n'est pas recommandé de naviguer entre les formes et les connecteurs sur le diagramme. Il est préférable de parcourir les relations dans le modèle, déplaçant entre les formes et les connecteurs uniquement lorsque cela est nécessaire pour travailler sur l'apparence du diagramme. Ces méthodes permettent de lier des connecteurs aux formes à chaque extrémité :

personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes

connector.FromShape, connector.ToShape

De nombreuses formes sont composés des ; elles se composent d'une forme parent et d'un ou plusieurs couches d'enfants. Formes qui sont positionnés par rapport à une autre forme sont dits ses enfants. Lorsque la forme parent se déplace, le déplacement enfants avec lui.

Les enfants connexes peuvent apparaître à l'extérieur de la zone englobante de la forme parent. Les enfantsimbriqués apparaissent strictement à l'intérieur de les limites du parent.

Pour obtenir l'ensemble supérieur de formes sur un diagramme, utilisez :

Diagram.NestedChildShapes

Les classes ancêtres de formes et de connecteurs sont :

ModelElement

-- PresentationElement

-- ShapeElement

----- NodeShape

------- Diagram

------- YourShape

----- LinkShape

------- BinaryLinkShape

--------- YourConnector

Propriétés de formes et de connecteurs

Dans la plupart des cas, il n'est pas nécessaire d'apporter des modifications explicites aux formes. Lorsque vous avez modifié les éléments de modèle, « résolvez » les règles mettent à jour les formes et les connecteurs. Pour plus d'informations, consultez Propagation et réponse aux modifications en attente.

Toutefois, il est utile d'apporter des modifications explicites aux formes dans les propriétés qui sont indépendants des éléments de modèle. Par exemple, vous pouvez modifier ces propriétés :

  • Size - détermine la hauteur et la largeur de la forme.

  • Location - position par rapport à la forme ou au diagramme parente

  • StyleSet - l'ensemble des stylets et des pinceaux elle est utilisée pour dessiner une forme ou le connecteur

  • Hide - rend la forme invisible

  • Show - rend la forme visible après Hide()

créer un élément et sa forme

Lorsque vous créez un élément et l'incorporer dans l'arborescence des relations d'incorporation, une forme est créée automatiquement et qui lui est associée. Cette opération est exécutée par les règles de « corrections » exécutant à la fin de la transaction. Toutefois, la forme apparaît dans un emplacement automatique-assigné, et sa forme, couleur et d'autres fonctionnalités ont les valeurs par défaut. Pour contrôler la manière dont la forme est créée, vous pouvez utiliser la fonction de fusion. Vous devez d'abord ajouter les éléments à ajouter dans un ElementGroup, puis fusionnez le groupe dans le diagramme.

Cette méthode :

  • définit le nom, si vous avez assigné une propriété comme nom d'élément.

  • Observe les directives de fusion d'élément que vous avez spécifié dans la définition de langage spécifique à un domaine.

Cet exemple crée une forme à la position de la souris, lorsque l'utilisateur double-clique sur le diagramme. Dans la définition DÉSOLÉ pour cet exemple, la propriété d' FillColor d' ExampleShape a été exposée.

  using Microsoft.VisualStudio.Modeling;
  using Microsoft.VisualStudio.Modeling.Diagrams;
  partial class MyDiagram
  {
    public override void OnDoubleClick(DiagramPointEventArgs e)
    {
      base.OnDoubleClick(e);

      using (Transaction t = this.Store.TransactionManager
          .BeginTransaction("double click"))
      {
        ExampleElement element = new ExampleElement(this.Store);
        ElementGroup group = new ElementGroup(element);
         
        { // To use a shape of a default size and color, omit this block.
          ExampleShape shape = new ExampleShape(this.Partition);
          shape.ModelElement = element;
          shape.AbsoluteBounds = new RectangleD(0, 0, 1.5, 1.0);
          shape.FillColor = System.Drawing.Color.Azure;
          group.Add(shape);
        }

        this.ElementOperations.MergeElementGroupPrototype(
          this,
          group.CreatePrototype(),
          PointD.ToPointF(e.MousePosition));
        t.Commit();
      }
    }
  }

Si vous fournissez plusieurs forme, définissez leurs positions relatives à l'aide de AbsoluteBounds.

Vous pouvez également définir la couleur et les autres propriétés exposées les connecteurs à l'aide de cette méthode.

Utilisez des transactions

Les formes, les connecteurs et les diagrammes sont des sous-types d' ModelElement et actifs dans le magasin. Vous devez donc apporter des modifications apportées à ces uniquement à l'intérieur d'une transaction. Pour plus d'informations, consultez Comment : utiliser des transactions pour mettre à jour le modèle.

Vue du document et données du document

Diagramme de classes des types de diagramme standard

Partitions du magasin

Lorsqu'un modèle est chargé, le diagramme sans est chargé en même temps. en général, le modèle est chargé dans Store.DefaultPartition, et le contenu de diagramme est chargé dans une autre partition. Généralement, le contenu de chaque partition est chargé et enregistré dans un fichier séparé.

Voir aussi

Référence

ModelElement

Concepts

Validation dans un langage spécifique à un domaine

Comment : utiliser des transactions pour mettre à jour le modèle

Intégration de modèles à l'aide de Visual Studio Modelbus

Autres ressources

Génération de code à partir d'un langage spécifique à un domaine

Propagation et réponse aux modifications en attente