Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Du kan skriva kod för att skapa och ta bort modellelement, ange deras egenskaper och skapa och ta bort länkar mellan element. Alla ändringar måste göras i en transaktion. Om elementen visas i ett diagram kommer diagrammet att "åtgärdas" automatiskt i slutet av transaktionen.
En exempel-DSL-definition
Det här är huvuddelen av DslDefinition.dsl för exemplen i det här avsnittet:
Denna modell är en instans av detta DSL:
Referenser och namnområden
Om du vill köra koden i det här avsnittet bör du referera till:
Microsoft.VisualStudio.Modeling.Sdk.11.0.dll
Koden använder det här namnområdet:
using Microsoft.VisualStudio.Modeling;
Om du dessutom skriver koden i ett annat projekt än den där din DSL definieras, bör du importera sammansättningen som skapas av Dsl-projektet.
Navigera i modellen
Egenskaper
Domänegenskaper som du definierar i DSL-definitionen blir egenskaper som du kan komma åt i programkod:
Person henry = ...;
if (henry.BirthDate < 1500) ...
if (henry.Name.EndsWith("VIII")) ...
Om du vill ange en egenskap måste du göra det i en transaktion:
henry.Name = "Henry VIII";
Om en egenskaps typberäknas i DSL-definitionen kan du inte ange den. Mer information finns i Beräknade och anpassade lagringsegenskaper.
Relationships
Domänrelationer som du definierar i DSL-definitionen blir par med egenskaper, en i klassen i varje ände av relationen. Namnen på egenskaperna visas i diagrammet DslDefinition som etiketter på rollerna på varje sida av relationen. Beroende på rollens multiplicitet är egenskapens typ antingen klassen i andra änden av relationen eller en samling av den klassen.
foreach (Person child in henry.Children) { ... }
FamilyTreeModel ftree = henry.FamilyTreeModel;
Egenskaperna i motsatta ändar av en relation är alltid ömsesidiga. När en länk skapas eller tas bort uppdateras rollegenskaperna för båda elementen. Följande uttryck (som använder utvidgningarna av System.Linq) är alltid sant för relationen ParentsHaveChildren i exemplet.
(Person p) => p.Children.All(child => child.Parents.Contains(p))
&& p.Parents.All(parent => parent.Children.Contains(p));
ElementLänkar. En relation representeras också av ett modellelement som kallas länk, vilket är en instans av domänrelationstypen. En länk har alltid ett källelement och ett målelement. Källelementet och målelementet kan vara samma.
Du kan komma åt en länk och dess egenskaper:
ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);
// This is now true:
link == null || link.Parent == henry && link.Child == edward
Som standard får inte fler än en instans av en relation länka ett par modellelement. Men om flaggan i DSL-definitionen Allow Duplicates är sann för relationen kan det finnas fler än en länk och du måste använda GetLinks:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }
Det finns också andra metoder för att komma åt länkar. Till exempel:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }
Dolda roller. Om egenskapen Genereras i DSL-definitionen är false för en viss roll genereras ingen egenskap som motsvarar den rollen. Du kan dock fortfarande komma åt länkarna och gå igenom länkarna med hjälp av metoderna för relationen:
foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }
Det vanligaste exemplet är PresentationViewsSubject relationen, som länkar ett modellelement till formen som visar det i ett diagram:
PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape
Elementkatalogen
Du kan komma åt alla element i lagret med hjälp av elementkatalogen.
store.ElementDirectory.AllElements
Det finns också metoder för att hitta element, till exempel följande:
store.ElementDirectory.FindElements(Person.DomainClassId);
store.ElementDirectory.GetElement(elementId);
Åtkomst till klassinformation
Du kan få information om klasser, relationer och andra aspekter av DSL-definitionen. Till exempel:
DomainClassInfo personClass = henry.GetDomainClass();
DomainPropertyInfo birthProperty =
personClass.FindDomainProperty("BirthDate")
DomainRelationshipInfo relationship =
link.GetDomainRelationship();
DomainRoleInfo sourceRole = relationship.DomainRole[0];
De överordnade klasserna för modellelement är följande:
ModelElement – alla element och relationer är ModelElements
ElementLink – alla relationer är ElementLinks
Utföra ändringar i en transaktion
När programkoden ändrar något i Store måste den göra det i en transaktion. Detta gäller för alla modellelement, relationer, former, diagram och deras egenskaper. Mer information finns i Transaction.
Den mest praktiska metoden för att hantera en transaktion är med en using instruktion som omges av en try...catch instruktion:
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.
}
Du kan göra valfritt antal ändringar i en transaktion. Du kan öppna nya transaktioner i en aktiv transaktion.
Om du vill göra ändringarna permanenta bör Commit du göra transaktionen innan den tas bort. Om ett undantag inträffar som inte fångas i transaktionen återställs Store till dess tillstånd före ändringarna.
Skapa modellelement
Det här exemplet lägger till ett element i en befintlig modell:
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!
}
Det här exemplet illustrerar dessa viktiga punkter om att skapa ett element:
Skapa det nya elementet i en specifik partition i Store. För modellelement och relationer, men inte former, är detta vanligtvis standardpartitionen.
Gör den till målobjektet för en inbäddningsrelation. I DslDefinition i det här exemplet måste varje person vara målet för inbäddningsrelationen FamilyTreeHasPeople. För att uppnå detta kan vi antingen ange rollegenskapen FamilyTreeModel för personobjektet eller lägga till Person i egenskapen Personer i FamilyTreeModel-objektet.
Ställ in egenskaperna för ett nytt element, särskilt den egenskap för vilken
IsNameär sant i DslDefinition. Den här flaggan markerar egenskapen som används för att unikt identifiera elementet inom sin ägare. I det här fallet har egenskapen Namn den flaggan.DSL-definitionen för denna DSL måste ha lästs in i Store. Om du skriver ett tillägg, till exempel ett menykommando, är detta vanligtvis redan sant. I andra fall kan du uttryckligen läsa in modellen i Store eller använda ModelBus för att läsa in den. Mer information finns i Så här: Öppna en modell från fil i Programkod.
När du skapar ett element på det här sättet skapas en form automatiskt (om DSL:en har ett diagram). Den visas på en automatiskt tilldelad plats med standardform, färg och andra funktioner. Om du vill styra var och hur den associerade formen visas kan du läsa Skapa ett element och dess form.
Skapa relationslänkar
Det finns två relationer som definierats i DSL-exempeldefinitionen. Varje relation definierar en rollegenskap för klassen i varje ände av relationen.
Du kan skapa en instans av en relation på tre sätt. Var och en av dessa tre metoder har samma effekt:
Ange egenskapen för källrollspelaren. Till exempel:
familyTree.People.Add(edward);edward.Parents.Add(henry);
Ange egenskapen för målrollspelaren. Till exempel:
edward.familyTreeModel = familyTree;Multipliciteten för den här rollen är
1..1, så vi tilldelar värdet.henry.Children.Add(edward);Multipliciteten för den här rollen är
0..*, så vi lägger till i samlingen.
Skapa en explicit instans av relationen. Till exempel:
FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);
Den sista metoden är användbar om du vill ange egenskaper för själva relationen.
När du skapar ett element på det här sättet skapas automatiskt en koppling i diagrammet, men den har en standardform, färg och andra funktioner. Information om hur den associerade kontakten skapas finns i Skapa ett element och dess form.
Ta bort element
Ta bort ett element genom att anropa Delete():
henry.Delete();
Den här åtgärden tar också bort:
Relationslänkar till och från elementet. Innehåller till exempel
edward.Parentsinte längrehenry.Element i roller som
PropagatesDeleteflaggan är sann för. Formen som visar elementet tas till exempel bort.
Som standardinställning har varje inbäddningsrelation sant värde vid målrollen. Borttagningen henry tar inte bort familyTree, men familyTree.Delete() tar bort alla Persons.
Som standardinställning gäller inte PropagatesDelete rollerna i referensrelationer.
Du kan göra så att borttagningsreglerna utelämnar specifika spridningar när du tar bort ett objekt. Detta är användbart om du ersätter ett element för ett annat. Du anger GUID för en eller flera roller som borttagningen inte ska spridas för. GUID kan hämtas från relationsklassen:
henry.Delete(ParentsHaveChildren.SourceDomainRoleId);
(Det här exemplet skulle inte ha någon effekt, eftersom PropagatesDelete är false för rollerna i ParentsHaveChildren relationen.)
I vissa fall förhindras borttagningen av ett lås, antingen på elementet eller på ett element som skulle tas bort genom spridning. Du kan använda element.CanDelete() för att kontrollera om elementet kan tas bort.
Ta bort relationslänkar
Du kan ta bort en relationslänk genom att ta bort ett element från en rollegenskap:
henry.Children.Remove(edward); // or:
edward.Parents.Remove(henry); // or:
Du kan också ta bort länken explicit:
edwardHenryLink.Delete();
Dessa tre metoder har alla samma effekt. Du behöver bara använda en av dem.
Om rollen har 0..1 eller 1..1 multiplicity kan du ange den till null, eller till ett annat värde:
edward.FamilyTreeModel = null; eller:
edward.FamilyTreeModel = anotherFamilyTree;
Ordna om länkarna för en relation
Länkarna för en viss relation som hämtas eller riktas mot ett visst modellelement har en specifik sekvens. De visas i den ordning de lades till. Till exempel kommer det här uttalandet alltid att ge barnen i samma ordning:
foreach (Person child in henry.Children) ...
Du kan ändra ordningen på länkarna:
ParentsHaveChildren link = GetLink(henry,edward);
ParentsHaveChildren nextLink = GetLink(henry, elizabeth);
DomainRoleInfo role =
link.GetDomainRelationship().DomainRoles[0];
link.MoveBefore(role, nextLink);
Locks
Dina ändringar kan förhindras av ett lås. Lås kan ställas in på enskilda element, på partitioner och på lagringen. Om någon av dessa nivåer har ett lås som förhindrar den typ av ändring som du vill göra kan ett undantag utlöses när du försöker. Du kan ta reda på om lås anges med hjälp av element. GetLocks(), som är en tilläggsmetod som definieras i namnområdet Microsoft.VisualStudio.Modeling.Immutability.
Mer information finns i Definiera en låsningsprincip för att skapa Read-Only segment.
Kopiera och klistra in
Du kan kopiera element eller grupper av element till en 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>());
Elementen lagras som en serialiserad elementgrupp.
Du kan sammanfoga element från en IDataObject till en modell:
using (Transaction t = targetDiagram.Store.
TransactionManager.BeginTransaction("paste"))
{
adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}
Merge () kan acceptera antingen en PresentationElement eller en ModelElement. Om du ger det en PresentationElementkan du också ange en position i måldiagrammet som en tredje parameter.
Navigera och uppdatera diagram
I en DSL är domänmodellelementet, som representerar ett begrepp som Person eller Sång, skilt från formelementet, som representerar det du ser i diagrammet. Domänmodellelementet lagrar viktiga egenskaper och relationer för begreppen. Formelementet lagrar storleken, positionen och färgen på objektets vy i diagrammet och layouten för dess komponentdelar.
Presentationselement
I DSL-definitionen skapar varje element som du anger en klass som härleds från någon av följande standardklasser.
| Typ av element | Basklass |
|---|---|
| Domänklass | ModelElement |
| Domänrelation | ElementLink |
| Shape | NodeShape |
| Connector | BinaryLinkShape |
| Diagram | Diagram |
Ett element i ett diagram representerar vanligtvis ett modellelement. Vanligtvis (men inte alltid) representerar en NodeShape domänklassinstans och en BinaryLinkShape representerar en domänrelationsinstans. Relationen PresentationViewsSubject länkar en nod eller länkform till det modellelement som den representerar.
Varje nod eller länkform tillhör ett diagram. En binär länkform ansluter två nodformer.
Former kan ha underordnade former i två uppsättningar. En form i NestedChildShapes uppsättningen är begränsad till avgränsningsrutan för dess överordnade. En form i RelativeChildShapes listan kan visas utanför eller delvis utanför det överordnade objektets gränser, till exempel en etikett eller en port. Ett diagram har inget RelativeChildShapes och inget Parent.
Navigera mellan former och element
Domänmodellelement och formelement är relaterade till PresentationViewsSubject relationen.
// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape =
PresentationViewsSubject.GetPresentation(henry)
.FirstOrDefault() as PersonShape;
Samma relation länkar relationer till kopplingar i diagrammet.
Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
PresentationViewsSubject.GetPresentation(link)
.FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape
Den här relationen länkar också modellens rot till diagrammet:
FamilyTreeDiagram diagram =
PresentationViewsSubject.GetPresentation(familyTree)
.FirstOrDefault() as FamilyTreeDiagram;
Om du vill hämta modellelementet som representeras av en form använder du:
henryShape.ModelElement as Person
diagram.ModelElement as FamilyTreeModel
Navigera runt i diagrammet
I allmänhet är det inte lämpligt att navigera mellan former och kopplingar i diagrammet. Det är bättre att navigera i relationerna i modellen och bara flytta mellan formerna och kopplingarna när det är nödvändigt att arbeta med diagrammets utseende. Dessa metoder länkar anslutningar till figurerna i varje ände.
personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes
connector.FromShape, connector.ToShape
Många former är sammansatta; de består av en överordnad form och ett eller flera underordnade lager. Former som är placerade i förhållande till en annan form sägs vara dess underordnade. När den överordnade formen flyttas, rör sig barnen med den.
Relativa underordnade element kan visas utanför avgränsningsrutan för den överordnade formen. Kapslade barn visas strikt inom gränserna för det överordnade objektet.
Om du vill hämta den översta uppsättningen former i ett diagram använder du:
Diagram.NestedChildShapes
De överordnade klasserna för former och kopplingar är:
-- ShapeElement
----- NodeShape
------- Diagram
------- YourShape
----- LinkShape
------- BinaryLinkShape
--------- YourConnector
Egenskaper för former och kopplingar
I de flesta fall är det inte nödvändigt att göra explicita ändringar i former. När du har ändrat modellelementen uppdaterar "korrigeringsreglerna" formerna och kopplingarna. Mer information finns i Svara på och sprida ändringar.
Det är dock användbart att göra vissa explicita ändringar i former i egenskaper som är oberoende av modellelementen. Du kan till exempel ändra följande egenskaper:
Size - bestämmer formens höjd och bredd.
Location - position i förhållande till den överordnade formen eller diagrammet
StyleSet - den uppsättning pennor och penslar som används för att rita formen eller kopplingen
Hide - gör formen osynlig
Show - gör formen synlig efter en
Hide()
Skapa ett element och dess form
När du skapar ett element och länkar det till trädet för inbäddningsrelationer skapas och associeras en form automatiskt med det. Detta görs av de "korrigeringsregler" som körs i slutet av transaktionen. Formen visas dock på en automatiskt tilldelad plats och dess form, färg och andra funktioner har standardvärden. Om du vill styra hur formen skapas kan du använda sammanslagningsfunktionen. Du måste först lägga till de element som du vill lägga till i en ElementGroup och sedan sammanfoga gruppen i diagrammet.
Den här metoden:
Anger namnet om du har tilldelat en egenskap som elementnamn.
Observerar alla sammanslagningsdirektiv för element som du angav i DSL-definitionen.
Det här exemplet skapar en form vid muspositionen när användaren dubbelklickar på diagrammet. I DSL-definitionen för det här exemplet har egenskapen ExampleShape av FillColor exponerats.
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();
}
}
}
Om du anger mer än en form anger du deras relativa positioner med hjälp av AbsoluteBounds.
Du kan också ange färg och andra exponerade egenskaper för anslutningar med den här metoden.
Använd transaktioner
Figurer, kopplingar och diagram är undertyper av ModelElement och finns i Store. Du måste därför bara göra ändringar i dem i en transaktion. Mer information finns i Så här: Använd transaktioner för att uppdatera modellen.
Dokumentvy och dokumentdata
Lagring av partitioner
När en modell läses in läses det medföljande diagrammet in samtidigt. Vanligtvis läses modellen in i Store.DefaultPartition och diagraminnehållet läses in i en annan partition. Vanligtvis läses innehållet i varje partition in och sparas i en separat fil.