Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym temacie opisano strukturę pliku DslDefinition.dsl w projekcie Dsl rozwiązania Narzędzi językowych specyficznych dla domeny, które definiuje język specyficzny dla domeny. Plik DslDefinition.dsl opisuje klasy i relacje języka specyficznego dla domeny wraz z diagramem, kształtami, łącznikami, formatem serializacji i przybornikiem języka specyficznego dla domeny i jego narzędziami do edycji. W rozwiązaniu języka specyficznego dla domeny kod definiujący te narzędzia jest generowany zgodnie z informacjami w pliku DslDefinition.dsl.
Ogólnie rzecz biorąc, do edytowania pliku DslDefinition.dsl używa się Projektant języka specyficznego dla domeny. Jednak jego nieprzetworzona forma to XML i można otworzyć plik DslDefinition.dsl w edytorze XML. Warto zrozumieć, jakie informacje zawiera plik i jak jest on zorganizowany do celów debugowania i rozszerzeń.
Przykłady w tym temacie pochodzą z szablonu rozwiązania Diagram składników. Aby zobaczyć przykład, utwórz rozwiązanie językowe specyficzne dla domeny oparte na szablonie rozwiązania Modele składników. Po utworzeniu rozwiązania plik DslDefinition.dsl pojawi się w Projektant języka specyficznego dla domeny. Zamknij plik, kliknij go prawym przyciskiem myszy w Eksplorator rozwiązań, wskaż polecenie Otwórz za pomocą, kliknij pozycję Edytor XML, a następnie kliknij przycisk OK.
Sekcje pliku DslDefinition.dsl
Element główny to <Dsl>, a jego atrybuty identyfikują nazwę języka specyficznego dla domeny, przestrzeń nazw oraz główne i pomocnicze numery wersji do przechowywania wersji. Schemat DslDefinitionModel
definiuje zawartość i strukturę prawidłowego pliku DslDefinition.dsl.
Elementy podrzędne <elementu głównego dsl> są następujące:
Klasy
Ta sekcja definiuje każdą klasę domeny, która generuje klasę w wygenerowanym kodzie.
Relacje
Ta sekcja definiuje każdą relację w modelu. Źródło i element docelowy reprezentują obie strony relacji.
Typy
Ta sekcja definiuje każdy typ i jego przestrzeń nazw. Właściwości domeny mają dwa typy. DomainEnumerations
są definiowane w modelu i generują typy w pliku DomainModel.cs. ExternalTypes
odwołują się do typów zdefiniowanych gdzie indziej (takich jak String
lub Int32
) i nie generują żadnych elementów.
Kształty
W tej sekcji zdefiniowano kształty opisujące sposób wyświetlania modelu w projektancie. Te kształty geometryczne są mapowane na klasy w modelu w sekcji Diagram.
Łączniki
W tej sekcji zdefiniowano wygląd łączników wyświetlanych w projektancie. Te geometryczne opisy stylów są mapowane na określone relacje w modelu w sekcji Diagram.
XmlSerializationBehavior
W tej sekcji zdefiniowano schemat serializacji i podano dodatkowe informacje o tym, jak każda klasa jest zapisywana w pliku.
Explorerbehavior
W tej sekcji opisano sposób wyświetlania okna Eksploratora DSL podczas edytowania modelu przez użytkownika.
Połączenie ionBuilders
W tej sekcji zdefiniowano konstruktor połączeń dla każdego narzędzia łącznika (narzędzie do tworzenia linków między dowolnymi dwiema klasami, które można połączyć). Ta sekcja określa, czy można połączyć źródło i klasę docelową.
Diagram
Ta sekcja definiuje diagram i służy do określania właściwości, takich jak kolor tła i klasa główna. (Klasa główna jest klasą domeny reprezentowaną przez diagram jako całość). Sekcja Diagram zawiera również elementy ShapeMap i Połączenie orMap, które określają kształt lub łącznik reprezentujący każdą klasę domeny lub relację.
Projektant
Ta sekcja definiuje projektanta (edytora), który łączy przybornik, ustawienia walidacji, diagram i schemat serializacji. Sekcja Projektant definiuje również klasę główną modelu, która jest zwykle również klasą główną diagramu.
Eksplorator
W tej sekcji opisano zachowanie Eksploratora DSL (zdefiniowane w sekcji XmlSerializationBehavior).
Monikers w pliku DslDefinition.dsl
W całym pliku DslDefinition.dsl można używać elementów monikers do tworzenia odwołań krzyżowych do określonych elementów. Na przykład każda definicja relacji zawiera podsekcję Źródło i podsekcję Docelową. Każda podsekcja zawiera nazwę klasy obiektu, którą można połączyć z tą relacją:
<DomainRelationship ... Name="LibraryHasMembers" Namespace="ExampleNamespace" > <Source> <DomainRole ...>
<RolePlayer>
<DomainClassMoniker Name="Library" />
</RolePlayer>
</DomainRole>
</Source>
Zwykle przestrzeń nazw przywoływalnego elementu (w tym przykładzie Library
klasa domeny) jest taka sama jak element odwołujący się (w tym przypadku relacja domeny LibraryHasMembers). W takich przypadkach pseudonim musi podać tylko nazwę klasy. W przeciwnym razie należy użyć pełnego formularza /Namespace/Name:
<DomainClassMoniker Name="/ExampleNameSpace/Library" />
System moniker wymaga, aby element równorzędny w drzewie XML miał odrębne nazwy. Z tego powodu błędy walidacji występują, jeśli spróbujesz zapisać definicję języka specyficznego dla domeny, która ma na przykład dwie klasy o tej samej nazwie. Przed zapisaniem pliku DslDefinition.dsl należy zawsze poprawić takie błędy zduplikowane nazwy, aby można było go ponownie załadować później.
Każdy typ ma własny typ moniker: DomainClassMoniker, DomainRelationshipMoniker itd.
Typy
Sekcja Typy określa wszystkie typy, które plik DslDefinition.dsl zawiera jako typy właściwości. Te typy dzielą się na dwa rodzaje: typy zewnętrzne, takie jak System.String, i wyliczone typy.
Typy zewnętrzne
Przykład diagramu składników zawiera listę zestawu standardowych typów pierwotnych, chociaż są używane tylko niektóre z nich.
Każda definicja typu zewnętrznego składa się tylko z nazwy i przestrzeni nazw, takiej jak Ciąg i System:
<ExternalType Name="String" Namespace="System" />
Pełne nazwy typów są używane, zamiast równoważnych słów kluczowych kompilatora, takich jak "ciąg".
Typy zewnętrzne nie są ograniczone do standardowych typów bibliotek.
Wyliczenia
Typowa specyfikacja wyliczenia przypomina ten przykład:
<DomainEnumeration IsFlags="true" Name="PageSort" Namespace="Fabrikam.Wizard">
<Literals>
<EnumerationLiteral Name="Start" Value="1"/>
<EnumerationLiteral Name="Decision" Value="2"/>
</Literals>
</DomainEnumeration>
Atrybut IsFlags
określa, czy wygenerowany kod jest poprzedzony atrybutem [Flags]
Środowiska uruchomieniowego języka wspólnego (CLR), który określa, czy wartości wyliczenia mogą być łączone bitowo. Jeśli ten atrybut ma wartość true, należy określić wartość power-of-two dla wartości literału.
Klasy
Większość elementów w dowolnej definicji języka specyficznego dla domeny jest bezpośrednio lub pośrednio wystąpieniami DomainClass
programu . Podklasy DomainClass
include DomainRelationship
, Shape
, Connector
i Diagram
. Sekcja Classes
pliku DslDefinition.dsl zawiera listę klas domeny.
Każda klasa ma zestaw właściwości i może mieć klasę bazową. W przykładzie NamedElement
diagramu składników jest klasą abstrakcyjną, która ma właściwość, której typem Name
jest ciąg:
<DomainClass Id="ee3161ca-2818-42c8-b522-88f50fc72de8" Name="NamedElement" Namespace="Fabrikam.CmptDsl5" DisplayName="Named Element" InheritanceModifier="Abstract">
<Properties>
<DomainProperty Id="ef553cf0-33b5-4e34-a30b-cfcfd86f2261" Name="Name" DisplayName="Name" DefaultValue="" Category="" IsElementName="true">
<Type>
<ExternalTypeMoniker Name="/System/String" />
</Type>
</DomainProperty>
</Properties>
</DomainClass>
NamedElement
jest bazą kilku innych klas, takich jak Component
, która ma własne właściwości oprócz Name
właściwości, którą odziedziczyła z NamedElement
klasy . Węzeł podrzędny BaseClass zawiera odwołanie do nazwy moniker. Ponieważ przywoływała klasa znajduje się w tej samej przestrzeni nazw, w moniker wymagany jest tylko jego nazwa:
<DomainClass Name="Component" Namespace="Fabrikam.CmptDsl5" DisplayName="Component">
<BaseClass>
<DomainClassMoniker Name="NamedElement" />
</BaseClass>
<Properties>
<DomainProperty Name="Kind" DisplayName="Kind" >
<Type>
<ExternalTypeMoniker Name="/System/String" />
</Type>
</DomainProperty>
</Properties>
Każda klasa domeny (w tym relacje, kształty, łączniki i diagramy) może mieć następujące atrybuty i węzły podrzędne:
Identyfikator. Ten atrybut jest identyfikatorem GUID. Jeśli nie podasz wartości w pliku, Projektant języka specyficznego dla domeny utworzy wartość. (Na ilustracjach w tym dokumencie ten atrybut jest zwykle pomijany w celu zaoszczędzenia miejsca).
Nazwa i przestrzeń nazw. Te atrybuty określają nazwę i przestrzeń nazw klasy w wygenerowany kod. Razem muszą być unikatowe w języku specyficznym dla domeny.
DziedziczenieModyfikator. Ten atrybut jest "abstrakcyjny", "zapieczętowany" lub żaden.
Displayname. Ten atrybut to nazwa wyświetlana w oknie Właściwości . Atrybut DisplayName może zawierać spacje i inne znaki interpunkcyjne.
GeneratesDoubleDerived. Jeśli ten atrybut ma wartość true, są generowane dwie klasy, a jedna jest podklasą drugiej. Wszystkie wygenerowane metody znajdują się w bazie, a konstruktory znajdują się w podklasie. Ustawiając ten atrybut, można zastąpić dowolną wygenerowaną metodę w kodzie niestandardowym.
HasCustomConstructor. Jeśli ten atrybut ma wartość true, konstruktor zostanie pominięty z wygenerowanego kodu, aby można było napisać własną wersję.
Atrybuty. Ten atrybut zawiera atrybuty CLR wygenerowanej klasy.
Klasa BaseClass. Jeśli określisz klasę bazową, musi być tego samego typu. Na przykład klasa domeny musi mieć inną klasę domeny jako bazę, a kształt przedziału musi mieć kształt przedziału. Jeśli nie określisz klasy bazowej, klasa w wygenerowanym kodzie pochodzi ze standardowej klasy struktury. Na przykład klasa domeny pochodzi z klasy
ModelElement
.Właściwości. Ten atrybut zawiera właściwości, które są utrzymywane pod kontrolą transakcji i utrwalane podczas zapisywania modelu.
ElementMergeDirectives. Każda dyrektywa scalania elementów kontroluje sposób dodawania innego wystąpienia innej klasy do wystąpienia klasy nadrzędnej. Więcej szczegółów na temat dyrektyw scalania elementów można znaleźć w dalszej części tego tematu.
Klasa języka C# jest generowana dla każdej klasy domeny wymienionej
Classes
w sekcji . Klasy języka C# są generowane w pliku Dsl\GeneratedCode\DomainClasses.cs.
Właściwości
Każda właściwość domeny ma nazwę i typ. Nazwa musi być unikatowa w klasie domeny i jej przechodnich bazach.
Typ musi odwoływać się do jednego z wymienionych w Types
sekcji . Ogólnie rzecz biorąc, pseudonim musi zawierać przestrzeń nazw.
<DomainProperty Name="Name" DisplayName="Name" DefaultValue="" Category="" IsElementName="true">
<Type>
<ExternalTypeMoniker Name="/System/String" />
</Type>
</DomainProperty>
Każda właściwość domeny może również mieć następujące atrybuty:
IsBrowsable. Ten atrybut określa, czy właściwość jest wyświetlana w oknie Właściwości , gdy użytkownik kliknie obiekt klasy nadrzędnej.
IsUIReadOnly. Ten atrybut określa, czy użytkownik może zmienić właściwość w oknie Właściwości , czy za pomocą dekoratora, w którym jest wyświetlana właściwość.
Rodzaj. Ten atrybut można ustawić na Wartość Normal, Calculated lub CustomStorage. Jeśli ustawisz ten atrybut na Calculated, musisz podać kod niestandardowy określający wartość, a właściwość będzie tylko do odczytu. Jeśli ustawisz ten atrybut na CustomStorage, musisz podać kod, który pobiera i ustawia wartości.
IsElementName. Jeśli ten atrybut ma wartość true, jego wartość jest automatycznie ustawiana na unikatową wartość po utworzeniu wystąpienia klasy nadrzędnej. Ten atrybut można ustawić na wartość true tylko dla jednej właściwości w każdej klasie, która musi mieć typ ciągu. W przykładzie
Name
diagramu składników właściwość wNamedElement
pliku maIsElementName
ustawioną wartość true. Za każdym razem, gdy użytkownik tworzyComponent
element (który dziedziczy zNamedElement
), nazwa jest automatycznie inicjowana na wartość podobną do "Component6".DefaultValue
. Jeśli określono ten atrybut, określona wartość jest przypisywana do tego atrybutu dla nowych wystąpień tej klasy. W przypadkuIsElementName
ustawienia atrybut DefaultValue określa początkową część nowego ciągu.Kategoria to nagłówek, w którym właściwość będzie wyświetlana w oknie Właściwości .
Relacje
Sekcja Relationships
zawiera listę wszystkich relacji w języku specyficznym dla domeny. Każdy Domain Relationship
element jest binarny i kierowany, łącząc elementy członkowskie klasy źródłowej z elementami członkowskimi klasy docelowej. Klasy źródłowe i docelowe są zazwyczaj klasami domeny, ale relacje z innymi relacjami są również dozwolone.
Na przykład relacja Połączenie ion łączy elementy członkowskie klasy OutPort z członkami klasy InPort. Każde wystąpienie łącza relacji łączy wystąpienie elementu OutPort z wystąpieniem inPort. Ponieważ relacja jest wiele-do-wielu, każda outPort może mieć wiele linków Połączenie ion ze źródłami, a każde wystąpienie InPort może mieć wiele linków Połączenie ion, które go dotyczą.
Role źródłowe i docelowe
Każda relacja zawiera role źródłowe i docelowe, które mają następujące atrybuty:
Atrybut
RolePlayer
odwołuje się do klasy domeny połączonych wystąpień: OutPort dla źródła, InPort dla obiektu docelowego.Atrybut
Multiplicity
ma cztery możliwe wartości (ZeroMany, ZeroOne, One i OneMany). Ten atrybut odnosi się do liczby łączy tej relacji, które mogą być skojarzone z jednym graczem roli.Atrybut
PropertyName
określa nazwę używaną w klasie odgrywania roli w celu uzyskania dostępu do obiektów na drugim końcu. Ta nazwa jest używana w szablonie lub kodzie niestandardowym do przechodzenia przez relację. Na przykładPropertyName
atrybut roli źródłowej jest ustawiony naTargets
wartość . W związku z tym następujący kod będzie działać:OutPort op = ...; foreach (InPort ip in op.Targets) ...
Zgodnie z konwencją nazwy właściwości są w liczbie mnogiej, jeśli wielokrotność to ZeroMany lub OneMany.
Wielokrotność roli odnosi się do liczby ról przeciwnych, które mogą być skojarzone z każdym wystąpieniem tej roli. Na przykład w relacji ComponentHasPorts rola docelowa ma
RolePlayer
atrybut ustawiony na Port,PropertyName
atrybut ustawiony na Składnik iMultiplicity
atrybut ustawiony na ZeroOne. W związku z tym odpowiedni kod do użycia tej roli to:ComponentPort p = ...; Component c = p.Component; if (c != null) ...
Name
Rola jest nazwą używaną w klasie Relacja, aby odwoływać się do tego końca łącza. Zgodnie z konwencją nazwa roli jest zawsze pojedyncza, ponieważ każde łącze ma tylko jedno wystąpienie na każdym końcu. Poniższy kod będzie działać:Connection connectionLink = ...; OutPort op = connectionLink.Source;
Domyślnie
IsPropertyGenerator
atrybut ma wartość true. Jeśli ustawiono wartość false, w klasie Role Player nie zostanie utworzona żadna właściwość. (W takim przypadku ,op.Targets
na przykład, nie będzie działać). Jednak nadal istnieje możliwość użycia kodu niestandardowego do przechodzenia przez relację lub uzyskania dostępu do samych łączy, jeśli kod niestandardowy jawnie używa relacji:OutPort op = ...; foreach (InPort ip in Connection.GetTargets(op)) ... foreach (Connection link in Connection.GetLinksToTargets(op)) ...
Atrybuty relacji
Oprócz atrybutów i węzłów podrzędnych, które są dostępne dla wszystkich klas, każda relacja ma następujące atrybuty:
IsEmbedding. Ten atrybut logiczny określa, czy relacja jest częścią drzewa osadzania. Każdy model musi utworzyć drzewo z osadzanymi relacjami. W związku z tym każda klasa domeny musi być elementem docelowym co najmniej jednej relacji osadzania, chyba że jest ona katalogiem głównym modelu.
Elementy ZezwalajDuplikacje. Ten atrybut logiczny, który jest domyślnie fałszywy, ma zastosowanie tylko do relacji, które mają wieloznaczność "wiele" zarówno w źródle, jak i w obiekcie docelowym. Określa, czy użytkownicy języka mogą połączyć jedną parę elementów źródłowych i docelowych przez więcej niż jedno łącze tej samej relacji.
Projektant i karty przybornika
Główną częścią sekcji Projektant pliku DslDefinition.dsl jest element PrzybornikTab. Jeden projektant może mieć kilka z tych elementów, z których każdy reprezentuje sekcję na czele w przyborniku wygenerowanego projektanta. Każdy element ToolboxTab może zawierać co najmniej jeden element ElementTool, Połączenie ionTool lub oba te elementy.
Narzędzia elementów mogą tworzyć wystąpienia określonej klasy domeny. Gdy użytkownik przeciąga narzędzie elementu na diagram, wynik jest określany przez dyrektywy scalania elementów zgodnie z opisem w sekcji dotyczącej dyrektyw scalania elementów w dalszej części tego tematu.
Każde narzędzie połączenia może wywołać określonego konstruktora połączeń. Jeden konstruktor połączeń może utworzyć więcej niż jeden typ relacji, w zależności od tego, gdzie użytkownik klika mysz, zgodnie z opisem w sekcji dotyczącej konstruktorów połączeń.
Żaden typ narzędzia nie tworzy bezpośrednio kształtów ani łączników. Każde wystąpienie klasy domeny lub relacji domeny; Mapowania kształtów i Połączenie or określają, jak jest wyświetlana ta klasa domeny lub relacja domeny.
Ścieżki
Ścieżki domeny są wyświetlane w kilku lokalizacjach w pliku DslDefinition.dsl. Te ścieżki określają serię łączy z jednego elementu w modelu (czyli wystąpienia języka specyficznego dla domeny) do innego. Składnia ścieżki jest prosta, ale szczegółowa.
Ścieżki są wyświetlane w pliku DslDefinition.dsl w <DomainPath>...</DomainPath>
tagach. Mimo że ścieżki mogą przechodzić przez wiele linków, większość przykładów w praktyce przechodzi tylko jeden link.
Ścieżka składa się z sekwencji segmentów. Każdy segment jest przeskokiem z obiektu do łącza lub z łącza do obiektu. W związku z tym przeskoki zwykle są alternatywne w długiej ścieżce. Pierwszy przeskok jest z obiektu do łącza, drugi przeskok jest do obiektu na drugim końcu łącza, trzeci przeskok jest do następnego łącza itd. Okazjonalnym wyjątkiem od tej sekwencji jest sytuacja, w której relacja jest źródłem lub elementem docelowym innej relacji.
Każdy segment zaczyna się od nazwy relacji. W przeskoku object-to-link relacja poprzedza kropkę i nazwę właściwości: "Relationship . Property
". W przeskoku link-to-object relacja poprzedza wykrzyknik i nazwę roli: "Relationship ! Role
".
Przykład diagramu składnika zawiera ścieżkę w elemencie ParentElementPath w elemencie ShapeMap for InPort. Ta ścieżka rozpoczyna się w następujący sposób:
ComponentHasPorts.Component
W tym przykładzie InPort jest podklasą ComponentPort i ma relację ComponentHasPorts. Właściwość nosi nazwę Component( Składnik).
Podczas pisania języka C# względem tego modelu można przejść przez link w jednym kroku, używając właściwości generowanej przez relację dla każdej z klas, które ma ona związek:
InPort port; ... Component c = port.Component;
Należy jednak jawnie wykonać oba przeskoki w składni ścieżki. Ze względu na to wymaganie można łatwiej uzyskać dostęp do linku pośredniego. Poniższy kod kończy przeskok z linku do składnika:
ComponentHasPorts.Component / ! Component
(Możesz pominąć nazwę relacji, w której jest taka sama jak w poprzednim segmencie).
Dyrektywy scalania elementów
Gdy użytkownik języka przeciąga element z Przybornika na diagram, tworzone jest wystąpienie klasy narzędzia. Ponadto linki są tworzone między tym wystąpieniem a istniejącymi elementami modelu. Niektóre elementy, takie jak składniki lub komentarze, są tworzone, gdy użytkownik języka przeciąga je z przybornika na pustą część diagramu. Inne elementy są tworzone, gdy użytkownik języka przeciąga je na inne elementy hosta. Na przykład obiekt OutPort lub InPort jest tworzony, gdy użytkownik języka przeciąga go na składnik.
Potencjalna klasa hosta, taka jak Component, zaakceptuje nowy element tylko wtedy, gdy klasa hosta ma dyrektywę scalania elementów dla klasy nowego elementu. Na przykład węzeł DomainClass o nazwie ="Składnik" zawiera:
<DomainClass Name="Component" ...> ...
<ElementMergeDirective>
<Index>
<DomainClassMoniker Name="ComponentPort" />
</Index>
<LinkCreationPaths>
<DomainPath>ComponentHasPorts.Ports</DomainPath>
</LinkCreationPaths>
</ElementMergeDirective> ...
Pseudonim klasy, który znajduje się w węźle Indeks, odwołuje się do klasy elementu, który można zaakceptować. W tym przypadku ComponentPort jest abstrakcyjną klasą bazową InPort i OutPort. W związku z tym można zaakceptować jeden z tych elementów.
ComponentModel, klasa główna języka, zawiera dyrektywy scalania elementów dla składników i komentarzy. Użytkownik języka może przeciągać elementy dla tych klas bezpośrednio na diagram, ponieważ puste części diagramu reprezentują klasę główną. Jednak model ComponentModel nie ma dyrektywy scalania elementów dla ComponentPort. W związku z tym użytkownik języka nie może przeciągać poleceń InPorts lub OutPorts bezpośrednio na diagram.
Dyrektywa scalania elementów określa, jakie łącza lub linki są tworzone, aby nowy element mógł integrować lub scalać z istniejącym modelem. W przypadku elementu ComponentPort jest tworzone wystąpienie elementu ComponentHasPorts. Parametr DomainPath identyfikuje zarówno relację, jak i właściwość klasy nadrzędnej Ports, do której zostanie dodany nowy element.
Możesz utworzyć więcej niż jeden link w dyrektywie scalania elementów, dołączając więcej niż jedną ścieżkę tworzenia łącza. Jedna ze ścieżek musi być osadzona.
W ścieżce tworzenia łącza można użyć więcej niż jednego segmentu. W tym przypadku ostatni segment definiuje, jaki link należy utworzyć. Wcześniejsze segmenty przechodzą z klasy nadrzędnej do obiektu, z którego ma zostać utworzone nowe łącze.
Można na przykład dodać tę dyrektywę scalania elementu do klasy Component:
<DomainClass Name="Component" ...> ...
<ElementMergeDirective>
<Index>
<DomainClassMoniker Name="Comment"/>
</Index>
<LinkCreationPaths>
<DomainPath> ComponentModelHasComponents . ComponentModel / !ComponentModel / ComponentModelHasComments.Comments </DomainPath>
<DomainPath>CommentsReferenceComponents.Comments</DomainPath>
</LinkCreationPaths>
</ElementMergeDirective>
Użytkownicy języka mogą następnie przeciągnąć komentarz do składnika i automatycznie utworzyć nowy komentarz z linkiem do składnika.
Pierwsza ścieżka tworzenia linku przechodzi z Component
do ComponentModel
, a następnie tworzy wystąpienie relacji ComponentModelHasComments
osadzania . Druga ścieżka tworzenia linku tworzy link relacji odwołania KomentarzeReferenceComponents z składnika hosta do nowego komentarza. Wszystkie ścieżki tworzenia linków muszą zaczynać się od klasy hosta i muszą kończyć się linkiem, który krokuje do nowo utworzonej klasy.
Xmlclassdata
Każda klasa domeny (w tym relacje i inne podtypy) może zawierać dodatkowe informacje podane w węźle XmlClassData
, które są wyświetlane w XmlSerializationBehavior
sekcji pliku DslDefinition.dsl. Te informacje dotyczą konkretnie sposobu przechowywania wystąpień klasy w postaci serializowanej, gdy model jest zapisywany w pliku.
Znaczna część wygenerowanego kodu, który XmlSerializationBehavior
ma wpływ, znajduje się w elemecie Dsl\GeneratedCode\Serializer.cs
.
Każdy XmlClassData
węzeł zawiera następujące węzły podrzędne i atrybuty:
Węzeł moniker, który odwołuje się do klasy, do której mają zastosowanie dane.
XmlPropertyData dla każdej właściwości zdefiniowanej w klasie.
XmlRelationshipData dla każdej relacji źródłowej w klasie . (Relacje mają również własne węzły XmlClassData).
Atrybut ciągu TypeName , który określa nazwę klasy pomocnika serializacji w wygenerowany kod.
Ciąg ElementName , który określa tag XML serializacji wystąpień tej klasy. Zgodnie z konwencją element Nazwa_elementu jest zwykle taka sama jak nazwa klasy, z wyjątkiem pierwszej litery jest małe litery. Na przykład przykładowy plik modelu rozpoczyna się od następującego:
<componentModel ...
MonikerElementName w serializowanych plikach modelu użytkownika. Ten atrybut wprowadza pseudonim, który odwołuje się do tej klasy.
MonikerAttributeName, który identyfikuje nazwę atrybutu XML w moniker. W tym fragmentcie serializowanego pliku użytkownika autor języka specyficznego dla domeny zdefiniował nazwę MonikerElementName jako "inPortMoniker" i MonikerAttributeName jako "path":
<inPortMoniker path="//Component2/InPort1" />
Połączenie ionBuilders
Konstruktor połączeń jest definiowany dla każdego narzędzia połączenia. Każdy konstruktor połączeń składa się z co najmniej jednego elementu Link Połączenie Directive, z których każdy zawiera co najmniej jeden element SourceDirective i co najmniej jeden element TargetDirective. Po kliknięciu narzędzia połączenia użytkownik może uruchomić połączenie z dowolnego kształtu zamapowanego na element modelu, który zostanie wyświetlony na liście elementów SourceDirective. Połączenie można następnie wykonać na kształcie zamapowanym na element wyświetlany na liście elementów TargetDirective. Klasa tworzonej relacji zależy od elementu Link Połączenie Directive wyznaczonego przez miejsce rozpoczęcia połączenia.
Xmlpropertydata
Atrybut DomainPropertyMoniker identyfikuje właściwość, do której odwołują się dane. Ten atrybut musi być właściwością otaczającej klasy ClassData.
Atrybut XmlName nadaje odpowiednią nazwę atrybutu, tak jak powinien występować w pliku XML. Zgodnie z konwencją ten ciąg jest taki sam jak nazwa właściwości, z wyjątkiem pierwszej litery jest małą literą.
Domyślnie atrybut Reprezentacja jest ustawiony na Atrybut. Jeśli ustawienie Reprezentacja ma wartość Element, węzeł podrzędny zostanie utworzony w kodzie XML. Jeśli dla opcji Reprezentacja ustawiono wartość Ignoruj, właściwość nie jest serializowana.
Atrybuty IsMonikerKey i IsMonikerQualifier dają właściwości rolę identyfikującą wystąpienia klasy nadrzędnej. Można ustawić właściwość IsMonikerKey na wartość true dla jednej właściwości zdefiniowanej w klasie lub dziedziczonej przez klasę. Ten atrybut identyfikuje pojedyncze wystąpienie klasy nadrzędnej. Właściwość ustawiona na IsMonikerKey
jest zwykle nazwą lub innym identyfikatorem klucza. Na przykład Name
właściwość string jest kluczem moniker nazwanymElementem i jej klasami pochodnymi. Gdy użytkownik zapisze model do pliku, ten atrybut musi zawierać unikatowe wartości dla każdego wystąpienia, między elementami równorzędnymi w drzewie osadzonych relacji.
W serializowanym pliku modelu pełna moniker elementu jest ścieżką z katalogu głównego modelu w dół drzewa osadzania relacji, cytując klucz moniker w każdym momencie. Na przykład porty InPorts są osadzone w obszarze Składniki, które są z kolei osadzone w katalogu głównym modelu. W związku z tym prawidłowym pseudonimem jest:
<inPortMoniker name="//Component2/InPort1" />
Można ustawić atrybut IsMonikerQualifier dla właściwości string i zapewnić dodatkowy sposób konstruowania pełnej nazwy elementu. Na przykład w pliku DslDefinition.dsl przestrzeń nazw jest kwalifikatorem moniker.
Xmlrelationshipdata
W pliku modelu serializacji łącza (zarówno osadzania, jak i relacji odwołania) są reprezentowane przez węzły podrzędne źródła na końcu relacji. W przypadku osadzania relacji węzeł podrzędny zawiera poddrzewo. W przypadku relacji referencyjnych węzeł podrzędny zawiera pseudonim, który odwołuje się do innej części drzewa.
Atrybut XmlRelationshipData w atrybucie XmlClassData definiuje dokładnie sposób zagnieżdżania węzłów podrzędnych w elemecie źródłowym. Każda relacja, która jest źródłem klasy domeny, ma jeden atrybut XmlRelationshipData .
Atrybut DomainRelationshipMoniker identyfikuje jedną z relacji źródłowych w klasie .
Atrybut RoleElementName nadaje nazwę tagu XML, która otacza węzeł podrzędny w serializowanych danych.
Na przykład plik DslDefinition.dsl zawiera:
<XmlClassData ElementName="component" ...>
<DomainClassMoniker Name="Component" />
<ElementData>
<XmlRelationshipData RoleElementName="ports">
<DomainRelationshipMoniker Name="ComponentHasPorts" />
</XmlRelationshipData>
W związku z tym serializowany plik zawiera:
<component name="Component1"> <!-- parent -->
<ports> <!-- role -->
<outPort name="OutPort1"> <!-- child element -->
...
</outPort>
</ports> ...
Jeśli atrybut UseFullForm ma wartość true, zostanie wprowadzona dodatkowa warstwa zagnieżdżania. Ta warstwa reprezentuje samą relację. Atrybut musi być ustawiony na wartość true, jeśli relacja ma właściwości.
<XmlClassData ElementName="outPort">
<DomainClassMoniker Name="OutPort" />
<ElementData>
<XmlRelationshipData UseFullForm="true" RoleElementName="targets">
<DomainRelationshipMoniker Name="Connection" />
</XmlRelationshipData>
</ElementData>
</XmlClassData>
Serializowany plik zawiera:
<outPort name="OutPort1"> <!-- Parent -->
<targets> <!-- role -->
<connection sourceRoleName="X"> <!-- relationship link -->
<inPortMoniker name="//Component2/InPort1" /> <!-- child -->
</connection>
</targets>
</outPort>
(Relacja Połączenie ion ma własne dane klasy XML, które udostępniają nazwy elementów i atrybutów).
Jeśli atrybut OmitElement ma wartość true, nazwa roli relacji zostanie pominięta, co skraca serializowany plik i jest jednoznaczne, jeśli dwie klasy nie mają więcej niż jednej relacji. Na przykład:
<component name="Component3">
<!-- only one relationship could get here: -->
<outPort name="OutPort1">
<targets> ...
Serializacja definicji języka specyficznego dla domeny
Plik DslDefinition.dsl jest samym plikiem serializowanym i jest zgodny z definicją języka specyficznego dla domeny. Poniżej przedstawiono kilka przykładów definicji serializacji XML:
Dsl to węzeł RootClass i klasa diagramu. DomainClass, DomainRelationship i inne elementy są osadzone w obszarze
Dsl
.Klasy to RoleElementName relacji między językiem specyficznym dla domeny i domainClass.
<Dsl Name="CmptDsl5" ...>
<Classes>
<DomainClass Name="NamedElement" InheritanceModifier="Abstract" ...
- Atrybut XmlSerializationBehavior jest osadzony w ramach atrybutu
Dsl
, ale atrybut OmitElement został ustawiony na relacji osadzania. W związku z tym żaden atrybut nieRoleElementName
interweniuje. Natomiast atrybut ClassData jestRoleElementName
atrybutem relacji osadzania między atrybutem XmlSerializationBehavior a atrybutem XmlClassData .
<Dsl Name="CmptDsl5" ...> ...
<XmlSerializationBehavior Name="ComponentsSerializationBehavior" >
<ClassData>
<XmlClassData ...>...</XmlClassData>
<XmlClassData ...>...</XmlClassData>
- Połączenie orHasDecorators to relacja osadzania między
Connector
iDecorator
.UseFullForm
został ustawiony tak, aby nazwa relacji była wyświetlana z listą właściwości dla każdego łącza z obiektu Połączenie or. Jednak został również ustawiony tak,OmitElement
aby nieRoleElementName
ujął wielu łączy osadzonych wewnątrzConnector
elementu :
<Connector Name="AssociationLink" ...>
<ConnectorHasDecorators Position="TargetTop" ...>
<TextDecorator Name="TargetRoleName" />
</ConnectorHasDecorators>
<ConnectorHasDecorators Position="SourceTop" ...>
<TextDecorator Name="SourceRoleName" />
</ConnectorHasDecorators>
</Connector>
Kształty i Połączenie ory
Definicje kształtów i Połączenie or dziedziczą atrybuty i węzły podrzędne z klas domen oprócz następujących elementów:
Color
iLine``Style
atrybuty.ExposesFillColorAsProperty i kilka podobnych atrybutów. Te atrybuty logiczne tworzą odpowiednią zmienną właściwości przez użytkownika. Ogólnie rzecz biorąc, gdy użytkownik języka kliknie kształt na diagramie, właściwości wyświetlane w oknie Właściwości to wystąpienia klasy domeny, do którego jest mapowany kształt. Jeśli
ExposesFillColorAsProperty
ustawiono wartość true, zostanie również wyświetlona właściwość samego kształtu.ShapeHasDecorators. Wystąpienie tego atrybutu występuje dla każdego tekstu, ikony lub dekoratora rozwijania/zwijania. (W pliku
ShapeHasDecorators
DslDefinition.dsl jest relacją z ustawionąUseFullForm
wartością true).
Mapy kształtu
Mapy kształtów określają sposób wyświetlania wystąpień danej klasy domeny na ekranie reprezentowanych przez kształt. Mapy kształtów i łączników są wyświetlane w Diagram
sekcji pliku DslDefinition.dsl.
Podobnie jak w poniższym przykładzie, ShapeMap
elementy mają co najmniej pseudonim klasy domeny, pseudonim kształtu i ParentElementPath
elementu:
<ShapeMap>
<DomainClassMoniker Name="InPort" />
<ParentElementPath>
<DomainPath>ComponentHasPorts.Component/!Component</DomainPath>
</ParentElementPath>
<PortMoniker Name="InPortShape" />
</ShapeMap>
Podstawową funkcją ParentElementPath
elementu jest to, że ta sama klasa obiektów może być wyświetlana jako inny kształt w różnych kontekstach. Jeśli na przykład InPort
element może być również osadzony w komentarzu, InPort
może być wyświetlany jako inny kształt w tym celu.
Po drugie, ścieżka określa, jak kształt odnosi się do jego elementu nadrzędnego. Nie zdefiniowano struktury osadzania między kształtami w pliku DslDefinition.dsl. Należy wywnioskować strukturę z map kształtów. Element nadrzędny kształtu jest kształtem mapowanym na element domeny, który identyfikuje ścieżka elementu nadrzędnego. W takim przypadku ścieżka identyfikuje składnik, do którego InPort
należy. Na innej mapie kształtów klasa Component jest mapowana na element ComponentShape. W związku z tym nowy InPort
kształt jest kształtem podrzędnym jego składnika ComponentShape
.
Jeśli zamiast tego dołączono kształt InPort do diagramu, ścieżka elementu nadrzędnego musiałaby wykonać kolejny krok do modelu składnika, który jest mapowany na diagram:
ComponentHasPorts . Component / ! Component / ComponentModelHasComponents . ComponentModel / ! ComponentModel
Katalog główny modelu nie ma mapy kształtu. Zamiast tego katalog główny jest przywołyny bezpośrednio z diagramu, który ma Class
element:
<Diagram Name="ComponentDiagram" >
<Class>
<DomainClassMoniker Name="ComponentModel" />
</Class>...
Mapy dekoratora
Mapa dekoratora kojarzy właściwość w zamapowanej klasie z dekoratorem kształtu. Jeśli właściwość jest wyliczonym lub typem logicznym, jego wartość może określić, czy dekorator jest widoczny. Jeśli dekorator jest dekoratorem tekstu, wartość właściwości może być wyświetlana i użytkownik może ją edytować.
Kształt przedziału Mapy
Mapy kształtów przedziału są podtypami map kształtów.
Połączenie or Mapy
Minimalna mapa łącznika odwołuje się do łącznika i relacji:
<ConnectorMap>
<ConnectorMoniker Name="CommentLink" />
<DomainRelationshipMoniker Name="CommentsReferenceComponents" />
</ConnectorMap>
mapy Połączenie or mogą również zawierać mapy dekoratora.