Dostosowywanie narzędzi i przybornika

Należy zdefiniować elementy przybornika dla elementów, które mają zostać dodane przez użytkowników do swoich modeli. Istnieją dwa rodzaje narzędzi: narzędzia elementów i narzędzia połączenia. W wygenerowanym projektancie użytkownik może wybrać narzędzie elementu, aby przeciągnąć kształty do diagramu i wybrać narzędzie połączenia, aby narysować łącza między kształtami. Ogólnie rzecz biorąc, narzędzia elementów umożliwiają użytkownikom dodawanie wystąpień klas domen do swoich modeli, a narzędzia połączeń umożliwiają dodawanie wystąpień relacji domeny.

Sposób definiowania przybornika

W Eksploratorze DSL rozwiń węzeł Edytor i węzły pod nim. Zazwyczaj zobaczysz hierarchię podobną do następującej:

Editor
     Toolbox Tabs
        MyDsl          //a tab
           Tools
               ExampleElement      // an element tool
               ExampleRelationship // a connection tool

W tej części Eksploratora DSL można wykonywać następujące czynności:

  • Utwórz nowe karty. Karty definiują nagłówki sekcji w przyborniku.

  • Utwórz nowe narzędzia.

  • Kopiowanie i wklejanie narzędzi.

  • Przenieś narzędzia w górę lub w dół na liście.

  • Usuń karty i narzędzia.

Ważne

Aby dodać lub wkleić elementy w Eksploratorze DSL, kliknij prawym przyciskiem myszy dziadek nowego węzła. Aby na przykład dodać narzędzie, kliknij prawym przyciskiem myszy kartę, a nie węzeł Narzędzia . Aby dodać kartę, kliknij prawym przyciskiem myszy węzeł Edytor .

Właściwość Ikona przybornika każdego narzędzia odwołuje się do pliku mapy bitowej 16x16. Te pliki są zwykle przechowywane w folderze Dsl\Resources .

Właściwość Class narzędzia elementu odnosi się do konkretnej klasy domeny. Domyślnie narzędzie utworzy wystąpienia tej klasy. Można jednak napisać kod, aby narzędzie tworzyło grupy elementów lub elementów różnych typów.

Właściwość Połączenie ion Builder narzędzia połączenia odnosi się do konstruktora połączeń, który definiuje typy elementów, które narzędzie może połączyć, i jakie relacje tworzy między nimi. Konstruktory Połączenie ion są definiowane jako węzły w Eksploratorze DSL. Konstruktory Połączenie ion są tworzone automatycznie podczas definiowania relacji domeny, ale można napisać kod, aby je dostosować.

Aby dodać narzędzie do przybornika

  1. Zwykle narzędzie elementu jest tworzone po utworzeniu klasy kształtu i zamapowane na klasę domeny.

    Zwykle narzędzie łącznika jest tworzone po utworzeniu klasy łącznika i zamapowane na relację referencyjną.

  2. W Eksploratorze DSL rozwiń węzeł Edytor i węzeł Karty przybornika .

    Kliknij prawym przyciskiem myszy węzeł karty przybornika, a następnie kliknij polecenie Dodaj nowe narzędzie elementu lub Dodaj nowe narzędzie Połączenie ion.

  3. Ustaw właściwość Ikona przybornika, aby odwołać się do mapy bitowej 16x16.

    Jeśli chcesz zdefiniować nową ikonę, utwórz plik mapy bitowej w Eksplorator rozwiązań w folderze Dsl\Resources. Plik powinien mieć następujące wartości właściwości: Kompiluj zawartość akcji = ; Kopiuj do katalogu = wyjściowego Nie kopiuj.

  4. W przypadku narzędzia elementu: ustaw właściwość Class narzędzia tak, aby odwoływała się do konkretnej klasy domeny mapowanej na kształt.

    W przypadku narzędzia łącznika: ustaw właściwość Połączenie ion Builder narzędzia na jeden z elementów oferowanych na liście rozwijanej. Konstruktory Połączenie ion są tworzone automatycznie podczas mapowania łącznika na relację domeny. Jeśli łącznik został niedawno utworzony, zwykle należy wybrać skojarzonego konstruktora połączeń.

  5. Aby przetestować rozszerzenie DSL, naciśnij klawisz F5 lub CTRL+F5, a następnie w eksperymentalnym wystąpieniu programu Visual Studio otwórz przykładowy plik modelu. Nowe narzędzie powinno pojawić się w przyborniku. Przeciągnij go na diagram, aby sprawdzić, czy tworzy nowy element.

    Jeśli narzędzie nie zostanie wyświetlone, zatrzymaj eksperymentalny program Visual Studio. W menu Start systemu Windows wpisz resetuj program Visual Studio, a następnie uruchom polecenie Resetuj wystąpienie eksperymentalne programu Microsoft Visual Studio zgodne z wersją programu Visual Studio. W menu Kompilacja kliknij pozycję Kompiluj rozwiązanie. Następnie ponownie przetestuj rozszerzenie DSL.

Narzędzia dostosowywania elementów

Domyślnie narzędzie utworzy pojedyncze wystąpienie określonej klasy, ale można to zmienić na dwa sposoby:

  • Zdefiniuj dyrektywy scalania elementów w innych klasach, umożliwiając im akceptowanie nowych wystąpień tej klasy i umożliwienie im tworzenia dodatkowych linków podczas tworzenia nowego elementu. Możesz na przykład zezwolić użytkownikowi na usunięcie komentarza do innego elementu, a tym samym utworzyć łącze odwołania między nimi.

    Te dostosowania mają również wpływ na to, co się stanie, gdy użytkownik wkleja lub przeciąga i upuści element.

    Aby uzyskać więcej informacji, zobacz Dostosowywanie tworzenia i przenoszenia elementów.

  • Napisz kod, aby dostosować narzędzie, aby umożliwić tworzenie grup elementów. Narzędzie jest inicjowane przez metody w pliku ToolboxHelper.cs, które można zastąpić. Aby uzyskać więcej informacji, zobacz Tworzenie grup elementów na podstawie narzędzia.

Tworzenie grup elementów na podstawie narzędzia

Każde narzędzie elementu zawiera prototyp elementów, które powinny zostać utworzone. Domyślnie każde narzędzie elementów tworzy jeden element, ale istnieje również możliwość utworzenia grupy powiązanych obiektów za pomocą jednego narzędzia. W tym celu zainicjujesz narzędzie za pomocą elementu ElementGroupPrototype zawierającego powiązane elementy.

Poniższy przykład jest pobierany z języka DSL, w którym istnieje tranzystor typu. Każdy tranzystor ma trzy nazwane terminale. Narzędzie elementu dla tranzystorów przechowuje prototyp zawierający cztery elementy modelu i trzy linki relacji. Gdy użytkownik przeciągnie narzędzie na diagram, prototyp zostanie utworzone i połączone z katalogiem głównym modelu.

Ten kod zastępuje metodę zdefiniowaną w pliku Dsl\GeneratedCode\ToolboxHelper.cs.

Aby uzyskać więcej informacji na temat dostosowywania modelu przy użyciu kodu programu, zobacz Nawigowanie i aktualizowanie modelu w kodzie programu.

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;

  public partial class CircuitsToolboxHelper
  {
    /// <summary>
    /// Toolbox initialization, called for each element tool on the toolbox.
    /// This version deals with each Component subtype separately.
    /// </summary>
    /// <param name="store"></param>
    /// <param name="domainClassId">Identifies the domain class this tool should instantiate.</param>
    /// <returns>prototype of the object or group of objects to be created by tool</returns>
    protected override ElementGroupPrototype CreateElementToolPrototype(Store store, Guid domainClassId)
    {
        if (domainClassId == Transistor.DomainClassId)
        {
            Transistor transistor = new Transistor(store);

            transistor.Base = new ComponentTerminal(store);
            transistor.Collector = new ComponentTerminal(store);
            transistor.Emitter = new ComponentTerminal(store);

            transistor.Base.Name = "base";
            transistor.Collector.Name = "collector";
            transistor.Emitter.Name = "emitter";

            // Create an ElementGroup for the Toolbox.
            ElementGroup elementGroup = new ElementGroup(store.DefaultPartition);
            elementGroup.AddGraph(transistor, true);
            // AddGraph includes the embedded parts

            return elementGroup.CreatePrototype();
        }
        else
        {
            return base.CreateElementToolPrototype(store, domainClassId);
}  }    }

Dostosowywanie narzędzi Połączenie ion

Zazwyczaj narzędzie elementu jest tworzone podczas tworzenia nowej klasy łącznika. Alternatywnie można przeciążyć jedno narzędzie, zezwalając typom dwóch końców na określenie typu relacji. Można na przykład zdefiniować jedno narzędzie połączenia, które może tworzyć relacje person-person i relacje Person-Town.

narzędzia Połączenie ion wywołują konstruktorów połączeń. Użyj konstruktorów połączeń, aby określić, jak użytkownicy mogą łączyć elementy w wygenerowany projektant. konstruktorzy Połączenie ion określają elementy, które mogą być połączone, oraz rodzaj utworzonego między nimi łącza.

Podczas tworzenia relacji referencyjnej między klasami domeny zostanie automatycznie utworzony konstruktor połączeń. Możesz użyć tego konstruktora połączeń podczas mapowania narzędzia połączenia. Aby uzyskać więcej informacji na temat tworzenia narzędzi połączenia, zobacz Konfigurowanie przybornika.

Możesz zmodyfikować domyślnego konstruktora połączeń, aby mógł obsługiwać inny zakres typów źródłowych i docelowych oraz tworzyć różne typy relacji.

Można również napisać niestandardowy kod dla konstruktorów połączeń, aby określić klasy źródłowe i docelowe dla połączenia, zdefiniować typ połączenia i podjąć inne akcje skojarzone z tworzeniem połączenia.

Struktura konstruktorów Połączenie ion

Konstruktory Połączenie ion zawierają co najmniej jedną dyrektywę łączenia łącza, która określa relację domeny oraz elementy źródłowe i docelowe. Na przykład w szablonie rozwiązania Przepływ zadań w Eksploratorze DSL można zobaczyć pozycję CommentReferencesSubjectsBuilder. Ten konstruktor połączeń zawiera jedną dyrektywę połączenia łącza o nazwie CommentReferencesSubjects, która jest mapowana na relację relacji domeny CommentReferencesSubjects. Ta dyrektywa link connect zawiera dyrektywę roli źródłowej Comment , która wskazuje klasę domeny i docelową dyrektywę roli wskazującą klasę FlowElement domeny.

Używanie konstruktorów Połączenie ion w celu ograniczenia ról źródłowych i docelowych

Za pomocą konstruktorów połączeń można ograniczyć występowanie określonych klas w roli źródłowej lub docelowej danej relacji domeny. Na przykład może istnieć podstawowa klasa domeny, która ma relację domeny z inną klasą domeny, ale nie chcesz, aby wszystkie klasy pochodne klasy bazowej miały te same role w tej relacji. W rozwiązaniu przepływu zadań istnieją cztery konkretne klasy domen (StartPoint, EndPoint, MergeBranch i Synchronization), które dziedziczą bezpośrednio z abstrakcyjnej klasy domeny FlowElement, oraz dwie konkretne klasy domen (Task i ObjectInState), które dziedziczą pośrednio z niej. Istnieje również relacja referencyjna usługi Flow , która przyjmuje klasy domeny FlowElement zarówno w roli źródłowej, jak i docelowej. Jednak wystąpienie klasy domeny programu EndPoint nie powinno być źródłem wystąpienia relacji usługi Flow ani wystąpieniem klasy StartPoint być obiektem docelowym wystąpienia relacji usługi Flow . Konstruktor połączeń usługi FlowBuilder ma dyrektywę łączenia łącza o nazwie Flow, która określa, które klasy domen mogą odgrywać rolę źródłową (Task, MergeBranch, StartPoint i Synchronization) oraz które mogą odgrywać rolę docelową (MergeBranch, Endpoint i Synchronization).

Do konstruktora połączeń można dodać więcej niż jedną dyrektywę połączenia. Może to pomóc w ukryciu niektórych złożoności modelu domeny przed użytkownikami i uniemożliwić przybornikowi zbyt zaśmiecone. Możesz dodać dyrektywy łączenia linków dla kilku różnych relacji domeny do jednego konstruktora połączeń. Jednak należy połączyć relacje domeny, gdy wykonują one mniej więcej tę samą funkcję.

W rozwiązaniu Przepływ zadań narzędzie połączenia przepływu służy do rysowania wystąpień zarówno relacji przepływu, jak i domeny ObjectFlow . Konstruktor połączeń flowBuilder zawiera oprócz opisanej wcześniej dyrektywy Flow link connect dwie dyrektywy łączenia linków o nazwie ObjectFlow. Te dyrektywy określają, że wystąpienie relacji ObjectFlow może być rysowane między wystąpieniami klasy domeny ObjectInState lub z wystąpienia objectInState do wystąpienia zadania, ale nie między dwoma wystąpieniami zadania lub z wystąpienia zadania do wystąpienia obiektu ObjectInState. Jednak wystąpienie relacji przepływu może być rysowane między dwoma wystąpieniami zadania. Jeśli skompilujesz i uruchomisz rozwiązanie przepływu zadań, zobaczysz, że rysowanie przepływu z wystąpienia obiektu ObjectInState do wystąpienia zadania powoduje utworzenie wystąpienia obiektu ObjectFlow, ale rysowanie przepływu między dwoma wystąpieniami zadania tworzy wystąpienie przepływu.

Niestandardowy kod dla konstruktorów Połączenie ion

W interfejsie użytkownika istnieją cztery pola wyboru, które definiują różne typy dostosowywania konstruktorów połączeń:

  • Pole wyboru Akceptacja niestandardowa w dyrektywie roli źródłowej lub docelowej

  • Pole wyboru Łączenie niestandardowe w dyrektywie roli źródłowej lub docelowej

  • Pole wyboru Używa połączenia niestandardowego w dyrektywie connect

  • właściwość Is Custom konstruktora połączeń

    Musisz podać kod programu, aby wprowadzić te dostosowania. Aby dowiedzieć się, jaki kod należy podać, zaznacz jedno z tych pól, kliknij pozycję Przekształć wszystkie szablony, a następnie skompiluj rozwiązanie. Zostanie wyświetlony raport o błędach. Kliknij dwukrotnie raport o błędach, aby wyświetlić komentarz wyjaśniający, jaki kod należy dodać.

Uwaga

Aby dodać kod niestandardowy, utwórz definicję klasy częściowej w pliku kodu niezależnie od plików kodu w folderach GeneratedCode. Aby uniknąć utraty pracy, nie należy edytować wygenerowanych plików kodu. Aby uzyskać więcej informacji, zobacz Zastępowanie i rozszerzanie wygenerowanych klas.

Tworzenie niestandardowego kodu Połączenie ion

W każdej dyrektywie łączenia linków karta Dyrektywy roli źródła definiuje typy, które można przeciągać. Podobnie karta Dyrektywy roli Docelowej definiuje typy, które można przeciągać. Dla każdego typu można dodatkowo określić, czy zezwalać na połączenie (dla tej dyrektywy connect link), ustawiając flagę Niestandardowe akceptowanie , a następnie podając dodatkowy kod.

Możesz również dostosować, co ma miejsce po nawiązaniu połączenia. Można na przykład dostosować tylko przypadek, w którym przeciąganie następuje do lub z określonej klasy, wszystkie przypadki, których zarządza jedna dyrektywa łączenia łącza, lub cały konstruktor połączenia FlowBuilder. Dla każdej z tych opcji można ustawić flagi niestandardowe na odpowiednim poziomie. Po przekształceniu wszystkich szablonów i próbie skompilowania rozwiązania komunikaty o błędach kierują Cię do komentarzy w wygenerowany kod. Komentarze te identyfikują, co należy podać.

W przykładzie Diagram składników konstruktor połączeń dla relacji domeny Połączenie ion jest dostosowany w celu ograniczenia połączeń, które można nawiązać między portami. Na poniższej ilustracji pokazano, że można tworzyć połączenia tylko z OutPort elementów do InPort elementów, ale można zagnieżdżać składniki wewnątrz siebie.

Połączenie ion przychodzący do outportu ze składnika zagnieżdżonego

Connection Builder

W związku z tym możesz określić, że połączenie może pochodzić ze składnika zagnieżdżonego do outPort. Aby określić takie połączenie, należy ustawić opcję Użyj akceptacji niestandardowej dla typu InPort jako roli źródłowej i typu OutPort jako roli docelowej w oknie Szczegóły DSL, jak pokazano na poniższych ilustracjach:

Link Połączenie, dyrektywa w Eksploratorze DSL

Connection builder image

Link Połączenie, dyrektywa w oknie szczegółów DSL

Link connect directive in DSL Details window

Następnie należy podać metody w klasie Połączenie ionBuilder:

  public partial class ConnectionBuilder
  {
    /// <summary>
    /// OK if this component has children
    /// </summary>
    private static bool CanAcceptInPortAsSource(InPort candidate)
    {
       return candidate.Component.Children.Count > 0;
    }

    /// <summary>
    /// Only if source is on parent of target.
    /// </summary>
    private static bool CanAcceptInPortAndInPortAsSourceAndTarget                (InPort sourceInPort, InPort targetInPort)
    {
      return sourceInPort.Component == targetInPort.Component.Parent;
    }
// And similar for OutPorts...

Aby uzyskać więcej informacji na temat dostosowywania modelu przy użyciu kodu programu, zobacz Nawigowanie i aktualizowanie modelu w kodzie programu.

Możesz na przykład użyć podobnego kodu, aby uniemożliwić użytkownikom tworzenie pętli za pomocą linków nadrzędny-podrzędnych. Te ograniczenia są uznawane za ograniczenia "twarde", ponieważ użytkownicy nie mogą w żadnym momencie ich naruszać. Można również utworzyć testy weryfikacji "miękkie", które użytkownicy mogą tymczasowo pominąć, tworząc nieprawidłowe konfiguracje, których nie mogą zapisać.

Dobre rozwiązanie w zakresie definiowania konstruktorów Połączenie ion

Należy zdefiniować jednego konstruktora połączeń, aby utworzyć różne typy relacji tylko wtedy, gdy są one powiązane koncepcyjnie. W przykładzie przepływu zadań używasz tego samego konstruktora do tworzenia przepływów między zadaniami, a także między zadaniami i obiektami. Jednak użycie tego samego konstruktora do tworzenia relacji między komentarzami i zadaniami byłoby mylące.

Jeśli zdefiniujesz konstruktor połączeń dla wielu typów relacji, upewnij się, że nie może być zgodny z więcej niż jednym typem z tej samej pary obiektów źródłowych i docelowych. W przeciwnym razie wyniki będą nieprzewidywalne.

Kod niestandardowy służy do stosowania ograniczeń "twardych", ale należy rozważyć, czy użytkownicy powinni mieć możliwość tymczasowego nawiązywania nieprawidłowych połączeń. Jeśli tak, możesz zmodyfikować ograniczenia, tak aby połączenia nie były weryfikowane, dopóki użytkownicy nie spróbują zapisać zmian.