Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Írhat kódot a modellelemek létrehozásához és törléséhez, a tulajdonságok beállításához, valamint az elemek közötti hivatkozások létrehozásához és törléséhez. Minden módosítást egy tranzakción belül kell végrehajtani. Ha az elemeket egy diagramon tekinti meg, a diagram automatikusan "javítva" lesz a tranzakció végén.
Példa DSL-definícióra
Ez a DslDefinition.dsl fő része a jelen témakör példáihoz:
Ez a modell ennek a DSL-nek az egy konkrét példája.
Hivatkozások és névterek
A kód ebben a témakörben való futtatásához a következőre kell hivatkoznia:
Microsoft.VisualStudio.Modeling.Sdk.11.0.dll
A kód a következő névteret fogja használni:
using Microsoft.VisualStudio.Modeling;
Ezenkívül, ha a kódot egy másik projektben írja, mint amelyikben a DSL definiálva van, importálja a Dsl-projekt által létrehozott szerelvényt.
A modell navigálása
Tulajdonságok
A DSL-definícióban definiált tartománytulajdonságok a programkódban elérhető tulajdonságokká válnak:
Person henry = ...;
if (henry.BirthDate < 1500) ...
if (henry.Name.EndsWith("VIII")) ...
Ha egy tulajdonságot szeretne beállítani, ezt egy tranzakción belül kell megtennie:
henry.Name = "Henry VIII";
Ha a DSL-definícióban egy tulajdonság TípusaSzámított, akkor nem állíthatja be. További információ: Számított és egyéni tárolótulajdonságok.
Relationships
A DSL-definícióban definiált tartománykapcsolatok tulajdonságok párjaivá válnak, amelyek a kapcsolat mindkét végén az osztályban vannak. A tulajdonságok neve a DslDefinition diagramban címkékként jelenik meg a kapcsolat mindkét oldalán lévő szerepkörökön. A szerepkör többszöröződésétől függően a tulajdonság típusa lehet a kapcsolat másik végén lévő osztály, vagy az osztály gyűjteménye.
foreach (Person child in henry.Children) { ... }
FamilyTreeModel ftree = henry.FamilyTreeModel;
A kapcsolat ellentétes végén lévő tulajdonságok mindig kölcsönösek. Hivatkozás létrehozásakor vagy törlésekor a szerepkör tulajdonságai mindkét elemen frissülnek. A következő kifejezés (amely a bővítményeket System.Linqhasználja) mindig igaz a ParentsHaveChildren kapcsolatra a példában:
(Person p) => p.Children.All(child => child.Parents.Contains(p))
&& p.Parents.All(parent => parent.Children.Contains(p));
ElementLinks. A kapcsolatokat egy hivatkozásnak nevezett modellelem is képviseli, amely a tartománykapcsolattípus egy példánya. A hivatkozásoknak mindig van egy forráseleme és egy céleleme. A forráselem és a célelem lehet ugyanaz.
A hivatkozásokat és azok tulajdonságait a következő címen érheti el:
ParentsHaveChildren link = ParentsHaveChildren.GetLink(henry, edward);
// This is now true:
link == null || link.Parent == henry && link.Child == edward
Alapértelmezés szerint egy kapcsolat egynél több példánya nem kapcsolhat össze modellelemeket. Ha azonban a DSL-definícióban a Allow Duplicates jelölő igaz a kapcsolatra, akkor több hivatkozás is lehet, és a következőt kell használnia GetLinks:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinks(henry, edward)) { ... }
A hivatkozások elérésére más módszerek is léteznek. Például:
foreach (ParentsHaveChildren link in ParentsHaveChildren.GetLinksToChildren(henry)) { ... }
Rejtett szerepkörök. Ha a DSL-definícióban a Generált tulajdonsághamis egy adott szerepkörhöz, akkor a rendszer nem hoz létre olyan tulajdonságot, amely megfelel az adott szerepkörnek. Azonban továbbra is elérheti a hivatkozásokat, és a kapcsolat módszereivel lépkedhet a hivatkozások között:
foreach (Person p in ParentsHaveChildren.GetChildren(henry)) { ... }
A leggyakrabban használt példa a PresentationViewsSubject kapcsolat, amely egy modellelemet a diagramon megjelenítő alakzathoz kapcsol:
PresentationViewsSubject.GetPresentation(henry)[0] as PersonShape
Az elemkönyvtár
Az elemkönyvtár használatával elérheti az áruház összes elemét:
store.ElementDirectory.AllElements
Az elemek keresésére is vannak módszerek, például a következők:
store.ElementDirectory.FindElements(Person.DomainClassId);
store.ElementDirectory.GetElement(elementId);
Az osztályadatok elérése
Információt kaphat a DSL-definíció osztályairól, kapcsolatairól és egyéb aspektusairól. Például:
DomainClassInfo personClass = henry.GetDomainClass();
DomainPropertyInfo birthProperty =
personClass.FindDomainProperty("BirthDate")
DomainRelationshipInfo relationship =
link.GetDomainRelationship();
DomainRoleInfo sourceRole = relationship.DomainRole[0];
A modellelemek elődosztályai a következők:
ModelElement – minden elem és kapcsolat egy ModelElement
ElementLink – minden kapcsolat ElementLinks
Módosítások végrehajtása tranzakción belül
Amikor a programkód bármit módosít az Áruházban, azt tranzakción belül kell megtennie. Ez az összes modellelemre, kapcsolatra, alakzatra, diagramra és azok tulajdonságaira vonatkozik. További információért lásd Transaction.
A tranzakciók kezelésének legkényelmesebb módja egy using utasítás egy try...catch utasításban:
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.
}
Egy tranzakción belül tetszőleges számú módosítást hajthat végre. Egy aktív tranzakción belül új tranzakciókat nyithat meg.
A módosítások véglegesítéséhez a tranzakciót a véglegesítés előtt kell Commit végrehajtania. Ha olyan kivétel történik, amely nem jelenik meg a tranzakcióban, az Áruház a módosítások előtt visszaáll az állapotára.
Modellelemek létrehozása
Ez a példa egy elemet ad hozzá egy meglévő modellhez:
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!
}
Ez a példa az elemek létrehozásával kapcsolatos alapvető szempontokat mutatja be:
Hozza létre az új elemet az Áruház adott partíciójában. Modellelemek és kapcsolatok esetén, de alakzatok nem, ez általában az alapértelmezett partíció.
Tegye az beágyazási kapcsolat célpontjává. A példa DslDefinition elemében minden személynek a FamilyTreeHasPeople kapcsolat beágyazásának célja kell lennie. Ennek eléréséhez beállíthatjuk a Személy objektum FamilyTreeModel szerepkörtulajdonságát, vagy hozzáadhatjuk a Személyt a FamilyTreeModel objektum Személyek szerepkörtulajdonságához.
Adja meg egy új elem tulajdonságait, különösen azt a tulajdonságot, amely
IsNamea DslDefinition tulajdonságban igaz. Ez a jelző jelöli azt a tulajdonságot, amely az elem tulajdonoson belüli egyedi azonosítására szolgál. Ebben az esetben a Name tulajdonságban ez a jelző szerepel.Ennek a DSL-nek a DSL-definícióját be kellett volna tölteni az Áruházba. Ha egy bővítményt, például egy menüparancsot ír, ez általában már igaz lesz. Más esetekben explicit módon betöltheti a modellt az Áruházba, vagy a ModelBus használatával is betöltheti. További információért lásd: Hogyan nyissunk meg egy modellt fájlból programkódban?.
Amikor ilyen módon hoz létre egy elemet, a rendszer automatikusan létrehoz egy alakzatot (ha a DSL-nek van diagramja). Automatikusan hozzárendelt helyen jelenik meg, alapértelmezett alakzattal, színnel és egyéb funkciókkal. Ha azt szeretné szabályozni, hogy a társított alakzat hol és hogyan jelenik meg, olvassa el az Elem és alakzat létrehozása című témakört.
Kapcsolathivatkozások létrehozása
A DSL-definícióban két kapcsolat van definiálva. Minden kapcsolat meghatároz egy szerepkörtulajdonságot az osztályban a kapcsolat mindkét végén.
Háromféleképpen hozhat létre egy kapcsolatpéldányt. A három módszer mindegyikének ugyanaz a hatása:
Állítsa be a forrásszereplő tulajdonságát. Például:
familyTree.People.Add(edward);edward.Parents.Add(henry);
Állítsa be a célszerepkör résztvevőjének tulajdonságát. Például:
edward.familyTreeModel = familyTree;Ennek a szerepkörnek a szorzása az
1..1, ezért hozzárendeljük az értéket.henry.Children.Add(edward);Ez a szerepkör többszörös előfordulása, így hozzáadjuk a gyűjteményhez.
Hozza létre a kapcsolat egy példányát explicit módon. Például:
FamilyTreeHasPeople edwardLink = new FamilyTreeHasPeople(familyTreeModel, edward);ParentsHaveChildren edwardHenryLink = new ParentsHaveChildren(henry, edward);
Az utolsó módszer akkor hasznos, ha a kapcsolat tulajdonságait szeretné beállítani.
Ha így hoz létre egy elemet, a rendszer automatikusan létrehoz egy összekötőt a diagramon, de az alapértelmezett alakzat, szín és egyéb funkciókkal rendelkezik. A társított összekötő létrehozásának szabályozásához tekintse meg az Elem és alakzat létrehozása című témakört.
Elemek törlése
Elem törlése hívással Delete():
henry.Delete();
Ez a művelet a következőt is törli:
Kapcsolati hivatkozások az elemhez és az elemből. Például a
edward.Parentstovábbiakban nem fog tartalmaznihenry.A szerepkörök azon elemei, amelyekre a
PropagatesDeletejelölő igaz. Az elemet megjelenítő alakzat például törlődik.
Alapértelmezés szerint minden beágyazási kapcsolat PropagatesDelete igaz a cél szerepkörre. A henry törlés nem törli a familyTreeelemet, hanem familyTree.Delete() az Personsösszeset törli.
Alapértelmezés szerint PropagatesDelete nem igaz a hivatkozási kapcsolatok szerepköreire nézve.
Előfordulhat, hogy a törlési szabályok bizonyos propagálásokat hagynak ki egy objektum törlésekor. Ez akkor hasznos, ha egy elemet egy másikra helyettesít. Adja meg egy vagy több szerepkör GUID-jait, amelyekhez a törlést nem szabad propagálni. A GUID a kapcsolatosztályból kérhető le:
henry.Delete(ParentsHaveChildren.SourceDomainRoleId);
(Ennek a konkrét példának nincs hatása, mert PropagatesDeletefalse a kapcsolat szerepköreihez ParentsHaveChildren tartozik.)
Bizonyos esetekben a törlést megakadályozza egy zárolás, akár az elemen, akár egy olyan elemen, amelyet propagálással törölnének.
element.CanDelete() Ezzel ellenőrizheti, hogy az elem törölhető-e.
Kapcsolathivatkozások törlése
Kapcsolathivatkozást úgy törölhet, ha eltávolít egy elemet egy szerepkörtulajdonságból:
henry.Children.Remove(edward); // or:
edward.Parents.Remove(henry); // or:
A hivatkozást explicit módon is törölheti:
edwardHenryLink.Delete();
Ennek a három módszernek ugyanaz a hatása. Csak egyet kell használnia.
Ha a szerepkör 0..1 vagy 1...1 szorzású, beállíthatja a következő értékre nullvagy másik értékre:
edward.FamilyTreeModel = null; vagy:
edward.FamilyTreeModel = anotherFamilyTree;
Kapcsolat hivatkozásainak újrarendezése
Egy adott modellelemhez forrásként vagy célként megadott kapcsolat hivatkozásai egy adott sorozatot tartalmaznak. A hozzáadásuk sorrendjében jelennek meg. Ez az állítás például mindig ugyanabban a sorrendben adja meg a gyermekeket:
foreach (Person child in henry.Children) ...
Módosíthatja a hivatkozások sorrendjét:
ParentsHaveChildren link = GetLink(henry,edward);
ParentsHaveChildren nextLink = GetLink(henry, elizabeth);
DomainRoleInfo role =
link.GetDomainRelationship().DomainRoles[0];
link.MoveBefore(role, nextLink);
Locks
A módosítások zárolással akadályozhatók meg. A zárolások beállíthatók az egyes elemeken, a partíciókon és az áruházban. Ha ezen szintek bármelyike olyan zárolással rendelkezik, amely megakadályozza a módosítani kívánt módosítást, a rendszer kivételt jelezhet a kísérlet során. Az elem.GetLocks() bővítménymetódusának használatával megállapíthatja, hogy a zárolások aktívak-e, amely a névtérben Microsoft.VisualStudio.Modeling.Immutability van definiálva.
További információ: Zárolási szabályzat definiálása Read-Only szegmensek létrehozásához.
Másolás és beillesztés
Elemeket vagy elemcsoportokat másolhat a IDataObjectkövetkezőbe:
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>());
Az elemek szerializált elemcsoportként vannak tárolva.
Az IDataObject elemeit egy modellbe egyesítheti:
using (Transaction t = targetDiagram.Store.
TransactionManager.BeginTransaction("paste"))
{
adopterShape.Diagram.ElementOperations.Merge(adopter, data);
}
Merge () elfogadhatja az a PresentationElement vagy a ModelElement. Ha ad neki egy PresentationElementhelyet, a céldiagramon is megadhat egy pozíciót harmadik paraméterként.
Diagramok navigálása és frissítése
A DSL-ben a tartománymodell eleme, amely egy olyan fogalmat jelöl, mint a Személy vagy a Dal, elkülönül az alakzatelemtől, amely a diagramon látható elemeket jelöli. A tartománymodell eleme tárolja a fogalmak fontos tulajdonságait és kapcsolatait. Az alakzatelem tárolja az objektum nézetének méretét, pozícióját és színét a diagramon, valamint az összetevők elrendezését.
Bemutatóelemek
A DSL-definícióban minden megadott elem létrehoz egy osztályt, amely a következő standard osztályok egyikéből származik.
| Elem típusa | Alaposztály |
|---|---|
| Tartományosztály | ModelElement |
| Tartománykapcsolat | ElementLink |
| Shape | NodeShape |
| Connector | BinaryLinkShape |
| Diagram | Diagram |
A diagram egy eleme általában egy modellelemet jelöl. Általában (de nem mindig) egy NodeShape egy tartományosztálypéldányt, és egy BinaryLinkShape egy tartománykapcsolati példányt jelöl. A PresentationViewsSubject kapcsolat összekapcsol egy csomópontot vagy egy csatolási alakzatot az általa képviselt modellelemhez.
Minden csomópont- vagy csatolási alakzat egy diagramhoz tartozik. A bináris csatolású alakzatok két csomópontalakzatot kötnek össze.
Az alakzatok gyermekalakzatokat tartalmazhatnak két halmazban. A NestedChildShapes halmazban lévő alakzat a szülő határolódobozában van korlátozva. A RelativeChildShapes listában szereplő alakzat a szülő határain kívül vagy részben kívül is megjelenhet – például címke vagy port. A diagramnak nincs RelativeChildShapes és Parent.
Navigálás alakzatok és elemek között
A tartománymodell elemei és az alakzatelemek kapcsolatban állnak a PresentationViewsSubject kapcsolattal.
// using Microsoft.VisualStudio.Modeling;
// using Microsoft.VisualStudio.Modeling.Diagrams;
// using System.Linq;
Person henry = ...;
PersonShape henryShape =
PresentationViewsSubject.GetPresentation(henry)
.FirstOrDefault() as PersonShape;
Ugyanez a kapcsolat összekapcsolja a kapcsolatokat a diagramon lévő összekötőkkel:
Descendants link = Descendants.GetLink(henry, edward);
DescendantConnector dc =
PresentationViewsSubject.GetPresentation(link)
.FirstOrDefault() as DescendantConnector;
// dc.FromShape == henryShape && dc.ToShape == edwardShape
Ez a kapcsolat a modell gyökerét a diagramhoz is csatolja:
FamilyTreeDiagram diagram =
PresentationViewsSubject.GetPresentation(familyTree)
.FirstOrDefault() as FamilyTreeDiagram;
A modellelem alakzattal való ábrázolásához használja a következőt:
henryShape.ModelElement as Person
diagram.ModelElement as FamilyTreeModel
Navigálás a diagram körül
Általában nem ajánlott navigálni az alakzatok és összekötők között a diagramon. Jobb, ha a modellben lévő kapcsolatokat navigálja, és csak akkor lépked az alakzatok és összekötők között, ha a diagram megjelenésén kell dolgoznia. Ezek a metódusok összekapcsolják az összekötőket a két végén lévő alakzatokkal:
personShape.FromRoleLinkShapes, personShape.ToRoleLinkShapes
connector.FromShape, connector.ToShape
Sok alakzat összetett; egy szülőalakzatból és egy vagy több gyermekrétegből állnak. A másik alakzathoz viszonyítva elhelyezett alakzatokat a rendszer gyermekeknek tekinti. Amikor a szülőalakzat mozog, a gyerekek vele együtt mozognak.
A relatív gyermekek a szülőalakzat határolókeretén kívül is megjelenhetnek. Beágyazott gyermekek szigorúan a szülői határokon belül jelennek meg.
A diagramon lévő alakzatok felső készletének beszerzéséhez használja a következőt:
Diagram.NestedChildShapes
Az alakzatok és összekötők elődosztályai a következők:
-- ShapeElement
----- NodeShape
------- Diagram
------- YourShape
----- LinkShape
------- BinaryLinkShape
--------- YourConnector
Alakzatok és összekötők tulajdonságai
A legtöbb esetben nem szükséges explicit módosításokat végezni az alakzatokon. Amikor módosította a modellelemeket, a "kiigazítás" szabályok frissítik az alakzatokat és az összekötőket. További információt a Változások megválaszolása és propagálása című témakörben talál.
Hasznos azonban, ha a modellelemekétől független tulajdonságok alakzatait explicit módon módosítja. Módosíthatja például ezeket a tulajdonságokat:
Size - meghatározza az alakzat magasságát és szélességét.
Location - a szülőalakzathoz vagy diagramhoz viszonyított pozíció
StyleSet - az alakzat vagy összekötő rajzolásához használt tollak és ecsetek készlete
Hide - az alakzatot láthatatlanná teszi
Show - az alakzat láthatóvá válik a
Hide()után
Egy elem és annak formájának létrehozása
Amikor létrehoz egy elemet, és összekapcsolja a kapcsolatok beágyazásának fájával, a rendszer automatikusan létrehoz és társít egy alakzatot. A tranzakció végén lefuttatott "fixup" szabályok hajtják ezt végre. Az alakzat azonban automatikusan hozzárendelt helyen jelenik meg, és az alakzat, a szín és más funkciók alapértelmezett értékekkel rendelkeznek. Az alakzat létrehozásának szabályozásához használhatja az egyesítési függvényt. Először fel kell vennie a hozzáadni kívánt elemeket egy Elemcsoportba, majd egyesítenie kell a csoportot a diagramban.
Ez a módszer:
Beállítja a nevet, ha elemnévként hozzárendelt egy tulajdonságot.
Megfigyeli a DSL-definícióban megadott elemegyesítési irányelveket.
Ez a példa létrehoz egy alakzatot az egér pozíciójában, amikor a felhasználó duplán kattint a diagramra. A minta DSL-definíciójában FillColor a ExampleShape tulajdonság ki lett téve.
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();
}
}
}
Ha egynél több alakzatot ad meg, állítsa be a relatív pozícióikat a AbsoluteBounds.
Ezzel a módszerrel az összekötők színét és egyéb közzétett tulajdonságait is beállíthatja.
Tranzakciók használata
Az alakzatok, összekötők és diagramok a ModelElement altípusai, és az Áruházban találhatók. Ezért csak egy tranzakción belül kell módosítania őket. További információért lásd: Hogyan használjuk a tranzakciókat a modell frissítéséhez.
Dokumentumnézet és dokumentumadatok
Tárolópartíciók
A modell betöltésekor a kapcsolódó diagram egyszerre lesz betöltve. A modell betöltése általában a Store.DefaultPartition szolgáltatásba történik, a diagram tartalma pedig egy másik partícióba töltődik be. Az egyes partíciók tartalma általában egy külön fájlba van betöltve és mentve.