Navegar y actualizar un modelo en el código del programa
Puede escribir código para crear y eliminar elementos de modelo, establecer sus propiedades, y para establecer y eliminar relaciones entre elementos. todos los cambios se deben realizar dentro de una transacción. Si los elementos se ven en un diagrama, el diagrama “se corregirá hacia arriba” automáticamente al final de la transacción.
En este tema
Una definición de ADSL de ejemplo
Navegar por el modelo
información de acceso de la clase
Realice los cambios dentro de una transacción
Crear elementos del modelo
crear vínculos de la relación
eliminar elementos
Eliminar los vínculos de la relación
Reordenar los vínculos de una Relación
Bloqueos
Copiar y pegar
Navegar y actualizar diagramas
Navegar entre las formas y elementos
Propiedades de formas y conectores
DocView y DocData
Formas, conectores y diagramas, y sus relaciones con los elementos del modelo se describen en un tema independiente. Para obtener más información, vea [redirigir] Cómo: Navegar y actualizar diagramas.
Una definición de ADSL de ejemplo
Es la parte principal de DslDefinition.dsl para los ejemplos de este tema:
Este modelo es una instancia de este ADSL:
referencias y espacios de nombres
Para ejecutar el código de este tema, debe hacer referencia:
Microsoft.VisualStudio.Modeling.Sdk.11.0.dll
El código usará este espacio de nombres:
using Microsoft.VisualStudio.Modeling;
Además, si está escribiendo el código en otro proyecto de en el que un DSL es definido, debe importar el ensamblado compilado en el proyecto del ADSL.
Navegar por el modelo
Propiedades
Las propiedades del dominio que define en la definición de ADSL se convierten en propiedades a los que puede tener acceso en el código del programa:
Person henry = ...;
if (henry.BirthDate < 1500) ...
if (henry.Name.EndsWith("VIII")) ...
Si desea establecer una propiedad, debe hacerlo dentro de transacción:
henry.Name = "Henry VIII";
Si en la definición de DSL, Tipo de una propiedad es calculado, no puede establecerlo. Para obtener más información, vea Propiedades calculadas y de almacenamiento personalizado.
Relaciones
Las relaciones de dominio que define en la definición de ADSL se convierten en pares de propiedades, una en la clase en cada extremo de la relación. Los nombres de las propiedades aparecen en el diagrama de DslDefinition como etiquetas en los roles en cada extremo de la relación. Dependiendo de la multiplicidad de rol, el tipo de la propiedad es la clase en el otro extremo de la relación, o una colección de esa clase.
foreach (Person child in henry.Children) { ... }
FamilyTreeModel ftree = henry.FamilyTreeModel;
Las propiedades de los extremos de contadores de una relación siempre son recíprocas. Cuando se crea o elimina un vínculo, se actualiza el rol de las propiedades en ambos elementos. La siguiente expresión (que utiliza las extensiones de System.Linq) siempre es true para la relación de ParentsHaveChildren en el ejemplo:
(Person p) => p.Children.All(child => child.Parents.Contains(p))
&& p.Parents.All(parent => parent.Children.Contains(p));
ElementLinks. Una relación también se representa mediante un elemento modelo denominado un vínculo, que es una instancia del tipo de relación del dominio. Un vínculo siempre tiene un elemento de origen y un elemento de destino. El elemento de origen y el elemento de destino pueden ser iguales.
Puede tener acceso a un vínculo y sus propiedades:
ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);
// This is now true:
link == null || link.Parent == henry && link.Child == edward
De forma predeterminada, no más de una instancia de una relación se permite enlazar cualquier par de elementos del modelo. Pero si en la definición de DSL, el indicador de Allow Duplicates es true para la relación, después puede haber más de un vínculo, y debe utilizar GetLinks:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }
También hay otros métodos para tener acceso a vínculos. Por ejemplo:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }
Roles ocultos. Si en la definición de DSL, es la propiedad generada es Falso para un rol determinado, no se genera ninguna propiedad correspondiente a ese rol. Sin embargo, todavía puede tener acceso a los vínculos y recorrer los vínculos mediante los métodos de la relación:
foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }
Frecuentemente el ejemplo utilizado es la relación de PresentationViewsSubject , que enlaza un elemento del modelo a la forma en la que se muestre en un diagrama:
PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape
El directorio del elemento
Puede obtener acceso a todos los elementos del almacén en el directorio del elemento:
store.ElementDirectory.AllElements
También hay métodos para buscar elementos, como el siguiente:
store.ElementDirectory.FindElements(Person.DomainClassId);
store.ElementDirectory.GetElement(elementId);
información de acceso de la clase
Puede recopilar información sobre las clases, las relaciones, y otros aspectos de la definición del ADSL. Por ejemplo:
DomainClassInfo personClass = henry.GetDomainClass();
DomainPropertyInfo birthProperty =
personClass.FindDomainProperty("BirthDate")
DomainRelationshipInfo relationship =
link.GetDomainRelationship();
DomainRoleInfo sourceRole = relationship.DomainRole[0];
Las clases del antecesor de elementos de modelo son las siguientes:
ModelElement todos los elementos y relaciones son ModelElements
ElementLink - todas las relaciones son ElementLinks
Realice los cambios dentro de una transacción
Cuando el código de programa cambia algo en el almacén, debe hacerlo dentro de una transacción. Esto se aplica a todos los elementos de modelo, relaciones, las formas, los diagramas, y sus propiedades. Para obtener más información, vea Transaction.
El método más cómoda de administrar una transacción está con una instrucción de using agregada en una instrucción de 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.
}
Puede realizar cualquier número de cambios dentro de una transacción. Puede abrir nuevas transacciones dentro de una transacción activa.
Para crear la permanente de los cambios, debe Commit la transacción antes de eliminar. Si se produce una excepción que no se detecta en la transacción, el almacén se restaurará el estado antes de los cambios.
Crear elementos del modelo
este ejemplo agrega un elemento a un modelo existente:
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!
}
Este ejemplo muestra estos puntos esenciales sobre cómo crear un elemento:
Cree el nuevo elemento en una partición específica del almacén. Para los elementos del modelo y las relaciones, pero no las formas, ésta suele ser la partición predeterminada.
Haga que sea el destino de una relación de incrustación. En el DslDefinition de este ejemplo, cada persona debe ser el destino de la relación FamilyTreeHasPeople de incrustación. Para ello, podemos o establecer propiedades de FamilyTreeModel el rol del objeto person, o agregue person de la propiedad de las personas al rol del objeto de FamilyTreeModel.
Establezca las propiedades de un nuevo elemento, especialmente la propiedad para el que IsName es true en el DslDefinition. Este mensaje indica la propiedad que se utiliza para identificar el elemento de forma única dentro de su propietario. En este caso, la propiedad name tiene ese mensaje.
La definición ADSL de este ADSL debe haberse cargado en el almacén. Si está escribiendo una extensión de como un comando de menú, este será normalmente ya true. En otros casos, puede cargar explícitamente el modelo en el almacén, o utilice ModelBus para cargarlo. Para obtener más información, vea Cómo: Abrir un modelo desde un archivo en el código del programa.
Cuando se crea un elemento de esta manera, una forma automáticamente se crea (si un ADSL tiene un diagrama). Aparece en una ubicación automáticamente asignada, de forma predeterminada, el color, y otras características. Si desea controlar dónde y cómo aparece la forma asociado, vea crear un elemento y su forma.
crear vínculos de la relación
Hay dos relaciones definidas en la definición de ADSL de ejemplo. Cada relación define un rol de la propiedad en la clase en cada extremo de la relación.
Hay tres maneras en que puede crear una instancia de una relación. cada uno de estos tres métodos tiene el mismo efecto:
Establezca la propiedad del encargado de función de origen. Por ejemplo:
familyTree.People.Add(edward);
edward.Parents.Add(henry);
Establezca la propiedad del encargado de función de destino. Por ejemplo:
edward.familyTreeModel = familyTree;
La multiplicidad de este rol es 1..1, se asigna en el valor.
henry.Children.Add(edward);
La multiplicidad de este rol es 0..*, por lo que se agregan a la colección.
Construye una instancia de la relación explícitamente. Por ejemplo:
FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);
ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);
El último método es útil si desea establecer las propiedades de la relación propio.
Cuando se crea un elemento de esta manera, un conector en el diagrama se crea automáticamente, pero tiene una forma predeterminada, el color, y otras características. para controlar cómo se crea el conector asociado, vea crear un elemento y su forma.
eliminar elementos
Eliminar un elemento llamando a Delete():
henry.Delete();
esta operación también eliminará:
Vínculos de la relación entre el elemento. Por ejemplo, edward.Parents no contendrá henry.
Elementos de los roles de los que el indicador de PropagatesDelete es true. Por ejemplo, la forma que muestra el elemento se eliminará.
De forma predeterminada, cada relación de incrustación tiene PropagatesDelete true en el rol de destino. Eliminar henry no elimina familyTree, pero familyTree.Delete() eliminaría todo el Persons. Para obtener más información, vea Personalizar el comportamiento de eliminación.
De forma predeterminada, PropagatesDelete no es true para los roles de relaciones de referencia.
Puede que las reglas de eliminación para omitir propagaciones concretas cuando se elimina un objeto. Esto es útil si está utilizando un elemento de otro. Se proporciona GUID de uno o más roles de los que la eliminación no se deben propagar. GUID se puede obtener de la clase de la relación:
henry.Delete(ParentsHaveChildren.SourceDomainRoleId);
(Este ejemplo concreto no tendría ningún efecto, porque PropagatesDelete es false para los roles de la relación de ParentsHaveChildren .)
En algunos casos, la eliminación es evitó la existencia de un bloqueo, en el elemento o en un elemento que se eliminó por la propagación. Puede utilizar element.CanDelete() para comprobar si el elemento se puede eliminar.
Eliminar los vínculos de la relación
Puede eliminar un vínculo de la relación quitar un elemento de un rol de propiedad:
henry.Children.Remove(edward); // or:
edward.Parents.Remove(henry); // or:
También puede eliminar el vínculo explícitamente:
edwardHenryLink.Delete();
estos tres métodos todos tienen el mismo efecto. Solo necesita usar uno de ellos.
Si el rol tiene multiplicidad 0..1 o 1..1, puede establecerlo en null, o a otro valor:
edward.FamilyTreeModel = null; //o:
edward.FamilyTreeModel = anotherFamilyTree;
Reordenar los vínculos de una Relación
Los vínculos de una relación determinada que son su origen o de destino en un elemento modelo determinado tienen una secuencia concreta. Aparecen en el orden en que se agregaron. por ejemplo, esta instrucción producirá siempre a los elementos secundarios en el mismo orden:
foreach (Person child in henry.Children) ...
Puede cambiar el orden de los vínculos:
ParentsHaveChildren link = GetLink(henry,edward);
ParentsHaveChildren nextLink = GetLink(henry, elizabeth);
DomainRoleInfo role =
link.GetDomainRelationship().DomainRoles[0];
link.MoveBefore(role, nextLink);
Bloqueos
Los cambios se pueden evitar por un bloqueo. Bloqueos puede establecerse en elementos individuales, en particiones y, en el almacén. Si cualquiera de estos niveles tienen un bloqueo que evite la clase de cambio que desea crear, una excepción podría producirse cuando se intenta. Puede detectar si bloquea están establecidos mediante el elemento. GetLocks(), que es un método de extensión que se define en Immutability.
Para obtener más información, vea Definir una directiva de bloqueo para crear segmentos de solo lectura.
Copiar y pegar
Puede copiar elementos o grupos de elementos a 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>());
Los elementos se almacenan como grupo serializado del elemento.
Puede combinar elementos de un IDataObject en un modelo:
using (Transaction t = targetDiagram.Store.
TransactionManager.BeginTransaction("paste"))
{
adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}
Merge () puede aceptar PresentationElement o ModelElement. Si se proporciona PresentationElement, también puede especificar una posición respecto al diagrama de destino como tercer parámetro.
Navegar y actualizar diagramas
En DSL, el elemento de modelo de dominio, que representa un concepto como persona o Song, es independiente del elemento de la forma, que representa lo que ve en el diagrama. El elemento de modelo de dominio almacena las propiedades y relaciones importantes de los conceptos. El elemento de la forma almacena el tamaño, la posición y el color de la vista del objeto en el diagrama, y el diseño de sus elementos.
Elementos de presentación
En la definición de DSL, cada elemento que se especifica crea una clase que sea derivada de una de las clases estándar siguientes.
clase de elemento |
Clase base |
---|---|
Clase de dominio |
|
Relación de dominio |
|
Forma |
|
conector |
|
Diagrama |
Un elemento de un diagrama representa normalmente un elemento de modelo. Normalmente (pero no siempre), NodeShape representa una instancia de clase de dominio, y BinaryLinkShape representa una instancia de la relación de dominio. La relación de PresentationViewsSubject vincula una forma de nodo o del vínculo al elemento de modelo que representa.
Cada forma de nodo o de vínculo pertenece a un diagrama. Una forma binaria de vínculo conecta dos formas de nodo.
las formas pueden tener formas secundarias en dos conjuntos. Una forma de NestedChildShapes establecido se restringe al cuadro de límite de su elemento primario. Una forma en la lista de RelativeChildShapes puede aparecer fuera de o en parte fuera de los límites del elemento primario (como una etiqueta o un puerto. un diagrama no tiene ningún RelativeChildShapes y ningún Parent.
Navegar entre las formas y elementos
Los elementos de modelo de dominio y los elementos de forma que están relacionados por la relación de PresentationViewsSubject .
// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape =
PresentationViewsSubject.GetPresentation(henry)
.FirstOrDefault() as PersonShape;
La misma relación vinculada relaciones a los conectores en el diagrama:
Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
PresentationViewsSubject.GetPresentation(link)
.FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape
Esta relación también vincula la raíz del modelo al diagrama:
FamilyTreeDiagram diagram =
PresentationViewsSubject.GetPresentation(familyTree)
.FirstOrDefault() as FamilyTreeDiagram;
para obtener el elemento modelo representado por una forma, utilice:
henryShape.ModelElement as Person
diagram.ModelElement as FamilyTreeModel
Navegar alrededor del diagrama
En general no se recomienda navegar entre las formas y conectores del diagrama. Es mejor navegar por las relaciones en el modelo, moviendo entre las formas y conectores cuando es necesario para trabajar en el aspecto del diagrama. Estos métodos vinculan los conectores a las formas en cada extremo:
personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes
connector.FromShape, connector.ToShape
muchas formas son compuestos; se componen de una forma primaria y uno o varios niveles de elementos secundarios. Las formas que se colocan en relación con otra forma se conocen a sus elementos secundarios. Cuando la forma primaria se mueve, los elementos secundarios se mueven con él.
Los elementos secundarios relativos pueden aparecer fuera del cuadro de límite de la forma primaria. Los elementos secundariosanidados aparecen estrictamente dentro de los límites del elemento primario.
Para obtener el conjunto superior de formas de un diagrama, utilice:
Diagram.NestedChildShapes
Las clases del antecesor de formas y conectores son:
-- ShapeElement
----- NodeShape
------- Diagram
------- TheShape
----- LinkShape
------- BinaryLinkShape
--------- TheConnector
Propiedades de formas y conectores
en la mayoría de los casos, no es necesario realizar cambios explícitos a las formas. Cuando haya cambiado los elementos de modelo, “corregir” reglas actualizan las formas y conectores. Para obtener más información, vea Responder a los cambios y propagarlos.
Sin embargo, es útil realizar algunos cambios explícitos a las formas en las propiedades que son independientes de los elementos del modelo. Por ejemplo, puede cambiar estas propiedades:
Size - determina el alto y el ancho de la forma.
Location - colocar en relación con la forma o el diagrama primaria
StyleSet - el conjunto de lápices y de pinceles utilizado para dibujar la forma o el conector
Hide - crea la forma no visible
Show - crea la forma visible después de Hide()
crear un elemento y su forma
Cuando se crea un elemento y vincularlo en el árbol de relaciones de incrustación, una forma es automáticamente creada y asociado. Esto se realiza mediante las reglas de “corrección” que se ejecutan al final de la transacción. sin embargo, la forma aparecerá en una ubicación automáticamente-asignada, y su forma, color y otras características tendrán valores predeterminados. Para controlar cómo se crea la forma, puede utilizar la función de la combinación. Primero debe agregar los elementos que desea incluir en un ElementGroup, y luego combinar el grupo en el diagrama.
Este método:
Establece el nombre, si ha asignado una propiedad como nombre de elemento.
Observe cualquier directiva de la combinación de elementos que especificó en la definición del ADSL.
Este ejemplo crea una forma en la posición del mouse, cuando el usuario hace doble clic en el diagrama. En la definición de ADSL para este ejemplo, la propiedad de FillColor de ExampleShape se ha expuesto.
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 se proporciona más de una forma, establezca sus posiciones relativas utilizando AbsoluteBounds.
También puede establecer el color y otras propiedades expuestas de conectores mediante este método.
Transacciones de uso
Formas, conectores y los diagramas son subtipos de ModelElement y se mantienen en el almacén. Debe por consiguiente realizar cambios a ellos solo dentro de una transacción. Para obtener más información, vea Cómo: Usar transacciones para actualizar el modelo.
Datos de la vista del documento y documentos
Particiones de almacén
Cuando un modelo cargado, el diagrama de acompañamiento se carga al mismo tiempo. Normalmente, el modelo se carga en Store.DefaultPartition, y el contenido del diagrama se carga en otro. Normalmente, el contenido de cada partición se carga y se guarda en un archivo independiente.
Vea también
Referencia
Conceptos
La validación en los lenguajes específicos de dominio
Cómo: Usar transacciones para actualizar el modelo
Integrar modelos utilizando Modelbus de Visual Studio