Udostępnij przez


Reguły propagują zmiany w modelu

Regułę sklepu można utworzyć, aby propagować zmianę z jednego elementu do innego w Visualizacji i Modelowania SDK (VMSDK). Gdy nastąpi zmiana dowolnego elementu w Sklepie, reguły mają być wykonywane, zwykle w przypadku zatwierdzenia najbardziej zewnętrznej transakcji. Istnieją różne typy reguł dla różnych rodzajów zdarzeń, takich jak dodawanie elementu lub usuwanie go. Reguły można dołączać do określonych typów elementów, kształtów lub diagramów. Wiele wbudowanych funkcji jest definiowanych przez reguły: na przykład reguły zapewniają, że diagram jest aktualizowany po zmianie modelu. Język specyficzny dla domeny można dostosować, dodając własne reguły.

Reguły sklepu są szczególnie przydatne do propagowania zmian w sklepie — czyli zmian w elementach modelu, relacjach, kształtach lub łącznikach, a także ich właściwości domenowych. Reguły nie są uruchamiane, gdy użytkownik wywołuje polecenia Cofnij lub Wykonaj ponownie. Zamiast tego menedżer transakcji upewnia się, że zawartość magazynu jest przywracana do prawidłowego stanu. Jeśli chcesz propagować zmiany do zasobów spoza sklepu, użyj Zdarzeń Sklepu. Aby uzyskać więcej informacji, zobacz Programy obsługi zdarzeń propagują zmiany poza modelem.

Załóżmy na przykład, że chcesz określić, że za każdym razem, gdy użytkownik (lub twój kod) tworzy nowy element typu ExampleDomainClass, dodatkowy element innego typu jest tworzony w innej części modelu. Możesz napisać element AddRule i skojarzyć go z exampleDomainClass. Możesz napisać kod w regule, aby utworzyć dodatkowy element.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Modeling;

namespace ExampleNamespace
{
 // Attribute associates the rule with a domain class:
 [RuleOn(typeof(ExampleDomainClass), FireTime=TimeToFire.TopLevelCommit)]
 // The rule is a class derived from one of the abstract rules:
 class MyAddRule : AddRule
 {
  // Override the abstract method:
  public override void ElementAdded(ElementAddedEventArgs e)
  {
    base.ElementAdded(e);
    ExampleDomainClass element = e.ModelElement;
    Store store = element.Store;
    // Ignore this call if we're currently loading a model:
    if (store.TransactionManager.CurrentTransaction.IsSerializing)
       return;

    // Code here propagates change as required - for example:
      AnotherDomainClass echo = new AnotherDomainClass(element.Partition);
      echo.Name = element.Name;
      echo.Parent = element.Parent;
    }
  }
 // The rule must be registered:
 public partial class ExampleDomainModel
 {
   protected override Type[] GetCustomDomainModelTypes()
   {
     List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
     types.Add(typeof(MyAddRule));
     // If you add more rules, list them here.
     return types.ToArray();
   }
 }
}

Uwaga / Notatka

Kod reguły powinien zmienić stan tylko elementów wewnątrz sklepu; oznacza to, że reguła powinna zmieniać tylko elementy modelu, relacje, kształty, łączniki, diagramy lub ich właściwości. Jeśli chcesz propagować zmiany do zasobów spoza magazynu, zdefiniuj zdarzenia sklepu. Aby uzyskać więcej informacji, zobacz Programy obsługi zdarzeń propagują zmiany poza modelem.

Aby zdefiniować regułę

  1. Zdefiniuj regułę jako klasę poprzedzoną atrybutem RuleOn . Atrybut kojarzy regułę z jedną z klas domeny, relacji lub elementów diagramu. Reguła zostanie zastosowana do każdego wystąpienia tej klasy, co może być abstrakcyjne.

  2. Zarejestruj regułę, dodając ją do zestawu zwróconego przez klasę modelu domeny GetCustomDomainModelTypes().

  3. Utwórz klasę reguł z jednej z abstrakcyjnych klas Reguł i napisz kod metody wykonywania.

    W poniższych sekcjach opisano te kroki bardziej szczegółowo.

Aby zdefiniować regułę dla klasy domeny

  • W pliku kodu niestandardowego zdefiniuj klasę i prefiks za pomocą atrybutu RuleOnAttribute :

    [RuleOn(typeof(ExampleElement),
         // Usual value - but required, because it is not the default:
         FireTime = TimeToFire.TopLevelCommit)]
    class MyRule ...
    
    
  • Typ tematu w pierwszym parametrze może być klasą domeny, relacją domeny, kształtem, łącznikiem lub diagramem. Zwykle reguły są stosowane do klas domen i relacji.

    Wartość FireTime to zwykle TopLevelCommit. Dzięki temu reguła jest wykonywana dopiero po wprowadzeniu wszystkich podstawowych zmian transakcji. Alternatywami są Inline, która wykonuje regułę wkrótce po zmianie; oraz LocalCommit, który wykonuje regułę na końcu bieżącej transakcji (co może nie być najbardziej zewnętrzną). Można również ustawić priorytet reguły, aby wpłynąć na jej kolejność w kolejce, ale jest to zawodna metoda osiągnięcia wymaganego wyniku.

  • Klasę abstrakcyjną można określić jako typ podmiotu.

  • Reguła ma zastosowanie do wszystkich wystąpień klasy podmiotu.

  • Wartością domyślną dla FireTime jest TimeToFire.TopLevelCommit. Powoduje to wykonanie reguły, gdy najbardziej zewnętrzna transakcja zostanie zatwierdzona. Alternatywą jest TimeToFire.Inline. Spowoduje to wykonanie reguły wkrótce po zdarzeniu wyzwalającym.

Aby zarejestrować regułę

  • Dodaj klasę reguł do listy typów zwracanych przez GetCustomDomainModelTypes w modelu domeny:

    public partial class ExampleDomainModel
     {
       protected override Type[] GetCustomDomainModelTypes()
       {
         List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
         types.Add(typeof(MyAddRule));
         // If you add more rules, list them here.
         return types.ToArray();
       }
     }
    
    
  • Jeśli nie masz pewności co do nazwy klasy modelu domeny, zajrzyj do pliku Dsl\GeneratedCode\DomainModel.cs

  • Napisz ten kod w niestandardowym pliku kodu w projekcie DSL.

Aby napisać kod reguły

  • Wyprowadź klasę reguł z jednej z następujących klas bazowych:

    Klasa bazowa Wyzwalacz
    AddRule Dodawany jest element, link lub kształt.

    Służy do wykrywania nowych relacji oprócz nowych elementów.
    ChangeRule Wartość właściwości domeny została zmieniona. Argument metody zawiera stare i nowe wartości.

    W przypadku kształtów ta reguła jest wyzwalana, gdy zmienia się wbudowana właściwość AbsoluteBounds, jeśli kształt zostanie przeniesiony.

    W wielu przypadkach wygodniej jest przesłonić OnValueChanged lub OnValueChanging w obsłudze właściwości. Te metody są wywoływane bezpośrednio przed i po zmianie. Natomiast reguła zwykle jest uruchamiana na końcu transakcji. Aby uzyskać więcej informacji, zobacz Procedury obsługi zmiany wartości właściwości domeny. Nuta: Ta reguła nie jest wyzwalana po utworzeniu lub usunięciu łącza. Zamiast tego napisz elementy AddRule i DeleteRule dla relacji domeny.
    DeletingRule Wyzwalane po usunięciu elementu lub łącza. Właściwość ModelElement.IsDeleting przyjmuje wartość logiczną "true" aż do zakończenia transakcji.
    DeleteRule Wykonywane po usunięciu elementu lub łącza. Reguła jest wykonywana po wykonaniu wszystkich innych reguł, w tym usuwania reguł. ModelElement.IsDeleting ma wartość false, a element ModelElement.IsDeleted ma wartość true. Aby umożliwić kolejne cofanie, element nie jest w rzeczywistości usuwany z pamięci, ale jest usuwany z store.ElementDirectory.
    MoveRule Element jest przenoszony z jednej partycji magazynu do innej.

    (Zwróć uwagę, że nie jest to związane z położeniem graficznym kształtu).
    RolePlayerChangeRule Ta reguła ma zastosowanie tylko do relacji domeny. Zostanie on wyzwolony, jeśli jawnie przypiszesz element modelu do dowolnego końca łącza.
    RolePlayerPositionChangeRule Wyzwalane, gdy kolejność łączy do lub z elementu jest zmieniana przy użyciu metod MoveBefore lub MoveToIndex w linku.
    TransactionBeginningRule Wykonywane po utworzeniu transakcji.
    TransactionCommittingRule Wykonywane, gdy transakcja ma zostać zatwierdzona.
    TransactionRollingBackRule Wykonywane, gdy transakcja ma zostać wycofana.
  • Każda klasa ma metodę, którą nadpisujesz. Wpisz override w swojej klasie, aby ją odnaleźć. Parametr tej metody identyfikuje element, który jest zmieniany.

    Zwróć uwagę na następujące kwestie dotyczące reguł:

  1. Zestaw zmian w transakcji może wyzwolić wiele reguł. Zwykle reguły są wykonywane po zatwierdzeniu najbardziej zewnętrznej transakcji. Są one wykonywane w nieokreślonej kolejności.

  2. Reguła jest zawsze wykonywana wewnątrz transakcji. W związku z tym nie trzeba tworzyć nowej transakcji w celu wprowadzania zmian.

  3. Reguły nie są wykonywane, gdy transakcja zostanie wycofana lub gdy są wykonywane operacje Cofnij lub Wykonaj ponownie. Te operacje resetują całą zawartość Sklepu do poprzedniego stanu. W związku z tym, jeśli reguła zmienia stan czegokolwiek poza Magazynem, może nie być zsynchronizowana z zawartością Sklepu. Aby zaktualizować stan aplikacji poza Store, zaleca się użycie zdarzeń. Aby uzyskać więcej informacji, zobacz Programy obsługi zdarzeń propagują zmiany poza modelem.

  4. Niektóre reguły są wykonywane, gdy model jest ładowany z pliku. Aby określić, czy ładowanie lub zapisywanie jest w toku, użyj polecenia store.TransactionManager.CurrentTransaction.IsSerializing.

  5. Jeśli kod reguły tworzy więcej wyzwalaczy reguły, zostaną one dodane na końcu listy uruchamiania i zostaną wykonane przed finalizacją transakcji. Instrukcje DeletedRules są wykonywane po wszystkich innych regułach. Jedna reguła może być uruchamiana wiele razy w transakcji, raz dla każdej zmiany.

  6. Aby przekazać informacje do i z reguł, możesz przechowywać informacje w pliku TransactionContext. Jest to tylko słownik, który jest utrzymywany podczas transakcji. Jest on usuwany po zakończeniu transakcji. Argumenty zdarzeń w każdej regule zapewniają dostęp do niego. Pamiętaj, że reguły nie są wykonywane w przewidywalnej kolejności.

  7. Użyj reguł po rozważeniu innych alternatyw. Jeśli na przykład chcesz zaktualizować właściwość po zmianie wartości, rozważ użycie właściwości obliczeniowej. Jeśli chcesz ograniczyć rozmiar lub lokalizację kształtu, użyj elementu BoundsRule. Jeśli chcesz odpowiedzieć na zmianę wartości właściwości, dodaj OnValueChanged procedurę obsługi do właściwości . Aby uzyskać więcej informacji, zobacz Odpowiadanie na zmiany i propagowanie ich.

Example

Poniższy przykład aktualizuje właściwość, gdy relacja domenowa jest instancjowana do połączenia dwóch elementów. Reguła zostanie wyzwolona nie tylko wtedy, gdy użytkownik utworzy link na diagramie, ale także jeśli kod programu utworzy łącze.

Aby przetestować ten przykład, utwórz DSL przy użyciu szablonu rozwiązania Task Flow i wstaw następujący kod w pliku w projekcie DSL. Skompiluj i uruchom rozwiązanie, a następnie otwórz przykładowy plik w projekcie Debugowanie. Rysuj łącze komentarza między kształtem komentarza a elementem przepływu. Tekst w komentarzu aktualizuje się, aby odzwierciedlić najnowszy element, z którym został połączony.

W praktyce zwykle należy napisać metodę DeleteRule dla każdego elementu AddRule.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;

namespace Company.TaskRuleExample
{

  [RuleOn(typeof(CommentReferencesSubjects))]
  public class RoleRule : AddRule
  {

    public override void ElementAdded(ElementAddedEventArgs e)
    {
      base.ElementAdded(e);
      CommentReferencesSubjects link = e.ModelElement as CommentReferencesSubjects;
      Comment comment = link.Comment;
      FlowElement subject = link.Subject;
      Transaction current = link.Store.TransactionManager.CurrentTransaction;
      // Don't want to run when we're just loading from file:
      if (current.IsSerializing) return;
      comment.Text = "Flow has " + subject.FlowTo.Count + " outgoing connections";
    }

  }

  public partial class TaskRuleExampleDomainModel
  {
    protected override Type[] GetCustomDomainModelTypes()
    {
      List<Type> types = new List<Type>(base.GetCustomDomainModelTypes());
      types.Add(typeof(RoleRule));
      return types.ToArray();
    }
  }

}