Поделиться через


Настройка создания и перемещения элементов

Можно разрешить перетаскивание элемента на другой элемент из панели элементов или в операции вставки или перемещения. Вы можете иметь перемещаемые элементы, связанные с целевыми элементами, с помощью указанных связей.

Директива слияния элементов (EMD) указывает, что происходит при объединении одного элемента модели в другой элемент модели. Это происходит в следующих случаях:

  • Пользователь перетаскивает из панели элементов на схему или фигуру.

  • Пользователь создает элемент с помощью меню "Добавить" в обозревателе или фигуре отсека.

  • Пользователь перемещает элемент из одной дорожки в другую.

  • Пользователь вставляет элемент.

  • Код программы вызывает директиву слияния элементов.

Хотя операции создания могут отличаться от операций копирования, они фактически работают одинаково. При добавлении элемента, например из панели элементов, прототип элемента реплика. Прототип объединяется в модель так же, как и элементы, скопированные из другой части модели.

Ответственность EMD заключается в том, чтобы решить, как объект или группа объектов должны быть объединены в определенное расположение в модели. В частности, он решает, какие связи следует создать, чтобы связать объединенную группу с моделью. Вы также можете настроить его для задания свойств и создания дополнительных объектов.

Diagram showing a before and after look at a tree of elements and their reference relationships when An E M D determines how a new element is added.

EmD создается автоматически при определении связи внедрения. По умолчанию EMD создает экземпляр связи при добавлении новых дочерних экземпляров в родительский объект. Эти ЭМД по умолчанию можно изменить, например, добавив пользовательский код.

Вы также можете добавить собственные EMD в определение DSL, чтобы позволить пользователям перетаскивать или вставлять различные сочетания объединенных и получающих классов.

Определение директивы слияния элементов

Директивы слияния элементов можно добавлять в классы домена, связи домена, фигуры, соединители и схемы. Их можно добавить или найти в DSL Обозреватель в классе получающего домена. Получающий класс — это класс домена элемента, который уже находится в модели, и с которым будет объединен новый или скопированный элемент.

Screenshot of DSL Explorer showing an E M D being added with ExampleElement selected as the Indexing class and the Applies to subclasses option checked.

Класс индексирования — это класс домена элементов, которые можно объединить в члены получающего класса. Экземпляры подклассов класса индексирования также будут объединены этим EMD, если только не задано значение False для подклассов .

Существует два типа директивы слияния:

  • Директива "Слияние процессов" указывает связи, с помощью которых новый элемент должен быть связан с деревом.

  • Директива "Переадресация слияния" перенаправляет новый элемент на другой получающий элемент, как правило, родительский элемент.

Вы можете добавить пользовательский код для директив слияния:

  • Set Использует настраиваемое принятие для добавления собственного кода, чтобы определить, следует ли объединить конкретный экземпляр элемента индексирования с целевым элементом. Когда пользователь перетаскивает с панели элементов, указатель "Недопустимый" показывает, запрещает ли код слиянию.

    Например, можно разрешить слияние только в том случае, если получающий элемент находится в определенном состоянии.

  • Set Использует пользовательское слияние для добавления собственного кода для определения изменений, внесенных в модель при выполнении слияния.

    Например, можно задать свойства в объединенном элементе с помощью данных из нового расположения в модели.

Примечание.

При написании пользовательского кода слияния он влияет только на слияния, выполняемые с помощью этого EMD. Если существуют другие EMD, которые объединяют тот же тип объекта или есть другой пользовательский код, который создает эти объекты без использования EMD, то они не будут затронуты пользовательским кодом слияния.

Если вы хотите убедиться, что новый элемент или новая связь всегда обрабатывается пользовательским кодом, рассмотрите возможность определения AddRule связи внедрения и DeleteRule класса домена элемента. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Пример. Определение EMD без пользовательского кода

В следующем примере пользователи могут создавать элемент и соединитель одновременно, перетаскивая из панели элементов на существующую фигуру. В примере добавляется EMD в определение DSL. Перед этим изменением пользователи могут перетаскивать инструменты на схему, но не на существующие фигуры.

Пользователи также могут вставлять элементы в другие элементы.

Предоставление пользователям одновременного создания элемента и соединителя

  1. Создайте новый DSL с помощью шаблона решения "Минимальный язык ".

    При запуске этого DSL он позволяет создавать фигуры и соединители между фигурами. Невозможно перетащить новую фигуру ExampleElement из панели элементов в существующую фигуру.

  2. Чтобы пользователи объединили элементы с ExampleElement фигурами, создайте новый EMD в ExampleElement классе домена:

    1. В Обозреватель DSL разверните классы домена. Щелкните правой кнопкой мыши ExampleElement и нажмите кнопку "Добавить директиву слияния элементов".

    2. Убедитесь, что откроется окно сведений DSL, чтобы просмотреть сведения о новом EMD. (Меню: View, Other Windows, DSL Details.)

  3. Задайте класс Индексирования в окне сведений DSL, чтобы определить, какой класс элементов можно объединить с ExampleElement объектами.

    В этом примере выберите ExampleElements, чтобы пользователь смог перетащить новые элементы на существующие элементы.

    Обратите внимание, что класс индексирования становится именем EMD в dsL Обозреватель.

  4. В разделе "Процесс слиянием", создав ссылки, добавьте два пути:

    • Один путь связывает новый элемент с родительской моделью. Выражение пути, которое необходимо ввести, переходит из существующего элемента до отношения внедрения к родительской модели. Наконец, он указывает роль в новой ссылке, к которой будет назначен новый элемент. Путь выглядит следующим образом:

      ExampleModelHasElements.ExampleModel/!ExampleModel/.Elements

    • Другой путь связывает новый элемент с существующим элементом. Выражение пути указывает связь ссылок и роль, к которой будет назначен новый элемент. Этот путь выглядит следующим образом:

      ExampleElementReferencesTargets.Sources

      С помощью средства навигации по пути можно создать каждый путь:

      1. В разделе " Процесс слиянием", создавая ссылки на пути, щелкните " <Добавить путь>".

      2. Щелкните стрелку раскрывающегося списка справа от элемента списка. Появится представление дерева.

      3. Разверните узлы в дереве, чтобы сформировать путь, который требуется указать.

  5. Проверьте DSL:

    1. Нажмите клавишу F5 , чтобы перестроить и запустить решение.

      Перестроение займет больше времени, чем обычно, так как созданный код будет обновлен из текстовых шаблонов, чтобы соответствовать новому определению DSL.

    2. При запуске экспериментального экземпляра Visual Studio откройте файл модели dsL. Создайте некоторые примеры элементов.

    3. Перетащите из средства "Пример элемента" в существующую фигуру.

      Появится новая фигура, связанная с существующей фигурой с соединителем.

    4. Скопируйте существующую фигуру. Выберите другую фигуру и вставьте.

      Создается копия первой фигуры. Он имеет новое имя, и он связан со второй фигурой с соединителем.

Обратите внимание на следующие моменты из этой процедуры:

  • Создавая директивы слияния элементов, можно разрешить любому классу элемента принимать любой другой. EMD создается в принимающем классе домена, а принятый класс домена указывается в поле класса Index.

  • Определив пути, можно указать, какие ссылки следует использовать для подключения нового элемента к существующей модели.

    Указанные ссылки должны содержать одну связь внедрения.

  • EMD влияет как на создание из панели элементов, так и на операции вставки.

    При написании пользовательского кода, создающего новые элементы, можно явно вызвать EMD с помощью ElementOperations.Merge метода. Это гарантирует, что код связывает новые элементы с моделью так же, как и другие операции. Дополнительные сведения см. в разделе "Настройка поведения копирования".

Пример. Добавление пользовательского кода accept в EMD

Добавив пользовательский код в EMD, можно определить более сложное поведение слияния. В этом простом примере пользователь не может добавлять больше фиксированного количества элементов на схему. В примере модифицируется EMD по умолчанию, которая сопровождает связь внедрения.

Написание пользовательского кода accept для ограничения того, что может добавить пользователь

  1. Создайте DSL с помощью шаблона минимального языкового решения. Откройте схему определения DSL.

  2. В Обозреватель DSL разверните классы домена, ExampleModelдирективы слияния элементов. Выберите директиву слияния элементов, которая называется ExampleElement.

    Этот EMD определяет, как пользователь может создавать новые ExampleElement объекты в модели, например перетаскивая с панели элементов.

  3. В окне сведений о DSL выберите "Использовать настраиваемое принятие".

  4. Заново постройте решение. Это займет больше времени, чем обычно, так как созданный код будет обновлен из модели.

    Появится сообщение об ошибке сборки, аналогичное: "Company.ElementMergeSample.ExampleElement не содержит определения для CanMergeExampleElement..."

    Необходимо реализовать метод CanMergeExampleElement.

  5. Создайте файл кода в проекте Dsl . Замените его содержимое следующим кодом и измените пространство имен на пространство имен проекта.

    using Microsoft.VisualStudio.Modeling;
    
    namespace Company.ElementMergeSample // EDIT.
    {
      partial class ExampleModel
      {
        /// <summary>
        /// Called whenever an ExampleElement is to be merged into this ExampleModel.
        /// This happens when the user pastes an ExampleElement
        /// or drags from the toolbox.
        /// Determines whether the merge is allowed.
        /// </summary>
        /// <param name="rootElement">The root element in the merging EGP.</param>
        /// <param name="elementGroupPrototype">The EGP that the user wants to merge.</param>
        /// <returns>True if the merge is allowed</returns>
        private bool CanMergeExampleElement(ProtoElementBase rootElement, ElementGroupPrototype elementGroupPrototype)
        {
          // Allow no more than 4 elements to be added:
          return this.Elements.Count < 4;
        }
      }
    }
    

    Этот простой пример ограничивает количество элементов, которые можно объединить в родительскую модель. Для более интересных условий метод может проверить любые свойства и ссылки принимающего объекта. Он также может проверить свойства элементов объединения, которые переносятся в ElementGroupPrototype. Дополнительные сведения см. в ElementGroupPrototypesразделе "Настройка поведения копирования". Дополнительные сведения о том, как писать код, считывающий модель, см. в статье Навигация и обновление модели в коде программы.

  6. Проверьте DSL:

    1. Нажмите клавишу F5 , чтобы перестроить решение. Когда откроется экспериментальный экземпляр Visual Studio, откройте экземпляр DSL.

    2. Создание новых элементов несколькими способами:

      • Перетащите из средства "Пример элемента " на схему.

      • В Обозреватель примера модели щелкните правой кнопкой мыши корневой узел и нажмите кнопку "Добавить новый пример".

      • Скопируйте и вставьте элемент на схеме.

    3. Убедитесь, что вы не можете использовать любой из этих способов добавления более четырех элементов в модель. Это связано с тем, что все они используют директиву слияния элементов.

Пример. Добавление пользовательского кода слияния в EMD

В пользовательском коде слияния можно определить, что происходит при перетаскивании средства или вставки в элемент. Существует два способа определения настраиваемого слияния:

  1. Set использует настраиваемое слияние и предоставляет необходимый код. Код заменяет созданный код слияния. Используйте этот параметр, если вы хотите полностью переопределить то, что выполняет слияние.

  2. Переопределите MergeRelate метод и при необходимости MergeDisconnect метод. Для этого необходимо задать свойство Generates Double Derived класса домена. Код может вызывать созданный код слияния в базовом классе. Используйте этот параметр, если вы хотите выполнить дополнительные операции после выполнения слияния.

    Эти подходы влияют только на слияния, выполняемые с помощью этого EMD. Если вы хотите повлиять на все способы создания объединенного элемента, альтернативой является определение AddRule связи внедрения и DeleteRule объединенного класса домена. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Переопределение MergeRelate

  1. В определении DSL убедитесь, что вы определили EMD, к которому требуется добавить код. Если вы хотите, можно добавить пути и определить пользовательский код принятия, как описано в предыдущих разделах.

  2. На схеме DslDefinition выберите класс получения слияния. Обычно это класс в конце исходной связи внедрения.

    Например, в dsL, созданном из решения "Минимальный язык", выберите ExampleModel.

  3. В окне "Свойства" задайте для свойства значение true.

  4. Заново постройте решение.

  5. Проверьте содержимое dsl\Generated Files\DomainClasses.cs. Выполните поиск именованных MergeRelate методов и проверьте их содержимое. Это поможет вам написать собственные версии.

  6. В новом файле кода напишите частичный класс для получающего класса и переопределите MergeRelate метод. Не забудьте вызвать базовый метод. Например:

    partial class ExampleModel
    {
      /// <summary>
      /// Called when the user drags or pastes an ExampleElement onto the diagram.
      /// Sets the time of day as the name.
      /// </summary>
      /// <param name="sourceElement">Element to be added</param>
      /// <param name="elementGroup">Elements to be merged</param>
      protected override void MergeRelate(ModelElement sourceElement, ElementGroup elementGroup)
      {
        // Connect the element according to the EMD:
        base.MergeRelate(sourceElement, elementGroup);
    
        // Custom actions:
        ExampleElement mergingElement = sourceElement as ExampleElement;
        if (mergingElement != null)
        {
          mergingElement.Name = DateTime.Now.ToLongTimeString();
        }
      }
    }
    

Написание пользовательского кода слияния

  1. В dsl\Generated Code\DomainClasses.cs проверьте методы с именем MergeRelate. Эти методы создают связи между новым элементом и существующей моделью.

    Кроме того, проверьте методы с именем MergeDisconnect. Эти методы отменяют связь элемента из модели при удалении.

  2. В Обозреватель DSL выберите или создайте директиву слияния элементов, которую требуется настроить. В окне сведений о DSL задайте настраиваемый слияние.

    При установке этого параметра параметры слияния и пересылки процесса игнорируются. Вместо этого используется код.

  3. Заново постройте решение. Это займет больше времени, чем обычно, так как созданные файлы кода будут обновлены из модели.

    Будут отображаться сообщения об ошибках. Дважды щелкните сообщения об ошибках, чтобы просмотреть инструкции в созданном коде. Эти инструкции просят предоставить два метода: MergeRelateYourDomainClass и MergeDisconnectYourDomainClass

  4. Напишите методы в определении частичного класса в отдельном файле кода. Примеры, которые вы проверили ранее, должны предложить необходимые сведения.

    Пользовательский код слияния не влияет на код, который создает объекты и связи напрямую, и он не влияет на другие EMD. Чтобы убедиться, что дополнительные изменения реализованы независимо от того, как создается элемент, рассмотрите возможность написания AddRule и DeleteRule вместо него. Дополнительные сведения см. в разделе "Правила распространения изменений в модели".

Перенаправление операции слияния

Директива прямого слияния перенаправляет цель операции слияния. Как правило, новый целевой объект является встраивающим родительским элементом исходного целевого объекта.

Например, в DSL, созданном с помощью шаблона схемы компонентов, порты внедрены в компоненты. Порты отображаются как небольшие фигуры на краю фигуры компонента. Пользователь создает порты, перетаскивая средство "Порт" в фигуру компонента. Но иногда пользователь ошибочно перетаскивает средство "Порт" на существующий порт, а не компонент, и операция завершается ошибкой. Это простая ошибка при наличии нескольких существующих портов. Чтобы помочь пользователю избежать этой неприятности, можно разрешить перетаскивать порты на существующий порт, но перенаправлять действие на родительский компонент. Операция работает так, как если бы целевой элемент был компонентом.

Директиву переадресации можно создать в решении модели компонентов. Если вы компилируете и запускаете исходное решение, вы увидите, что пользователи могут перетаскивать любое количество элементов входного порта или выходного порта из панели элементов в элемент Component. Однако они не могут перетащить порт в существующий порт. Недоступная указатель предупреждает их о том, что этот шаг не включен. Однако можно создать директиву прямого слияния, чтобы порт, который непреднамеренно удален на существующий порт ввода переадресовывали в элемент Component .

Создание директивы переадресации слиянием

  1. Создайте решение для языка для конкретного домена с помощью шаблона модели компонентов.

  2. Отображение Обозреватель DSL, открыв dslDefinition.dsl.

  3. В Обозреватель DSL разверните классы домена.

  4. Абстрактный класс домена ComponentPort — это базовый класс InPort и OutPort. Щелкните правой кнопкой мыши ComponentPort и нажмите кнопку "Добавить директиву слияния элементов".

    Новый узел директивы слияния элементов отображается в узле директив слияния элементов.

  5. Выберите узел директивы слияния элементов и откройте окно сведений DSL.

  6. В списке классов индексирования выберите ComponentPort.

  7. Выберите "Переадресовать слияние" в другой класс домена.

  8. В списке выбора пути разверните компонент ComponentPort, разверните компонент ComponentHasPorts и выберите компонент.

    Новый путь должен выглядеть следующим образом:

    ComponentHasPorts.Component/! Компонент

  9. Сохраните решение, а затем преобразуйте шаблоны, нажав кнопку справа на панели инструментов Обозреватель решений.

  10. Выполните сборку и запуск решения. Появится новый экземпляр Visual Studio.

  11. В Обозреватель решений откройте sample.mydsl. Появится схема и панель элементов ComponentLanguage.

  12. Перетащите порт ввода из панели элементов в другой порт ввода. Затем перетащите выходной порт в InputPort, а затем в другой выходной порт.

    Вы не увидите указатель недоступности, и вы сможете удалить новый порт ввода в существующем. Выберите новый порт ввода и перетащите его в другую точку компонента.