Настройка элементов и панели элементов
Для тех элементов, которые пользователи смогут добавлять в свои модели, необходимо определить содержание панели элементов. Панель элементов может содержать два вида средств: средства элемента и средства подключения. В созданном конструкторе пользователь может выбрать средство элемента, чтобы перетащить фигуры на схему, и средство подключения, чтобы протянуть связи между фигурами. В целом средства элемента позволяют пользователям добавлять в модели экземпляры классов доменов, а средства подключения — экземпляры доменных связей.
Содержание раздела
Определение панели элементов
Настройка средств элемента
Создание групп элементов из средства
Настройка средств подключения
Определение панели элементов
В Обозревателе DSL разверните узел "Редактор" и узлы под ним. Обычно при этом отрывается иерархия следующего вида:
Editor
Toobox Tabs
MyDsl //a tab
Tools
ExampleElement // an element tool
ExampleRelationship // a connection tool
В этой части Обозревателя DSL можно выполнять следующие действия.
Создавать новые таблицы. Вкладки определяют заголовки разделов в панели элементов.
Создавать новые средства.
Копировать и вставлять средства.
Перемещать средства вверх или вниз по списку.
Удалять вкладки и средства.
Важно!
Чтобы добавить или вставить элементы в Обозреватель DSL, щелкните прародителя нового узла правой кнопкой мыши.Например, чтобы добавить средство, щелкните правой кнопкой мыши вкладку (не узел) Средства.Чтобы добавить вкладку, щелкните правой кнопкой мыши узел Редактор.
Свойство Значок средства элемента каждого средства ссылается на файл точечного рисунка размером 16 x 16 пикселей. Обычно эти файлы хранятся в папке Dsl\Resources.
Свойство Класс средства элемента указывает на конкретный класс домена. По умолчанию средство будет создавать экземпляры данного класса. Тем не менее можно написать код, заставляющий средство создавать элементы или группы элементов другого типа.
Свойство Построитель подключений средства подключения указывает, какой построитель подключений определяет типы элементов, которые средство может подключать, и какие отношения он создает между ними. Построители подключений определяются в виде узлов в Обозревателе DSL. Построители подключений создаются автоматически при определении доменных связей, но могут также настраиваться с помощью кода.
Добавление средства в панель элементов
Средство элемента обычно создают после создания класса фигуры и его сопоставления с классом домена.
Средство подключения обычно создают после создания класса соединителя и его сопоставления со ссылочным отношением.
В Обозревателе DSL разверните узлы Редактор и Вкладки панели элементов.
Щелкните правой кнопкой мыши узел панели элементов и выберите команду Добавить новое средство элемента или Добавить новое средство подключения.
Выберите для свойства Значок средства элемента ссылку на файл точечного рисунка размером 16 x 16 пикселей.
Чтобы определить новый значок, создайте файл точечного рисунка в Обозревателе решений в папке Dsl\Resources. Файл должен иметь следующие значения свойств: Build Action = Content; Copy to Output Directory = Do not copy.
Для средства элемента: настройте свойство Класс средства на обозначение конкретного класса домена, сопоставляемого с фигурой.
Для средства подключения: настройте свойство Connection Builder средства на один из элементов, предлагаемых в раскрывающемся списке. Построители подключений автоматически создаются при сопоставлении соединителя с доменной связью. Сразу после создания соединителя, как правило, выбирается соответствующий построитель подключений.
Чтобы проверить DSL, нажмите клавишу F5 или сочетание клавиш CTRL + F5 и откройте в экспериментальном экземпляре Visual Studio пример файла модели. На панели элементов должно появиться новое средство. Перетащите его на схему, чтобы проверить, создает ли оно новый элемент.
Если средство не появляется, остановите экспериментальный экземпляр Visual Studio. В меню Windows Пуск запустите программу Сброс экспериментального экземпляра Microsoft Visual Studio 2010. В меню Visual Studio Построить выберите пункт Перестроить решение. Затем проверьте DSL еще раз.
Настройка средств элемента
По умолчанию средство создает один экземпляр указанного класса, но это можно изменять двумя описанными ниже способами.
Определить директивы слияния элемента с другими классами, позволив им принимать новые экземпляры этого класса и создавать дополнительные ссылки при создании нового элемента. Например, можно разрешить пользователю оставить комментарий на другой элемент и тем самым создать между ними справочную ссылку.
Эти настройки также влияют на процесс вставки и перетаскивания элемента.
Для получения дополнительной информации см. Customizing Element Creation and Movement.
Написать код, чтобы настроить средство на возможность создания групп элементов. Средство запускается методами из файла ToolboxHelper.cs, которые можно переопределить. Дополнительные сведения см. в разделе Создание групп элементов из средства.
Создание групп элементов из средства
Каждое средство элемента содержит прототип элементов, которые оно должно создавать. По умолчанию, каждое средство элемента создает один элемент, но может также создавать группу объектов, связанных с одним средством. Для этого запустите средство с помощью класса ElementGroupPrototype, который содержит связанные элементы.
Следующий пример взят из DSL, в котором есть тип "Транзистор". Каждый транзистор имеет три именованных контакта. Средство элемента для транзисторов хранит прототип, содержащий четыре элемента модели и три ссылки отношения. Когда пользователь перетаскивает средство на схему, создается экземпляр прототипа, который связывается с корнем модели.
Этот код переопределяет метод, определенный в файле Dsl\GeneratedCode\ToolboxHelper.cs.
Дополнительные сведения о настройке модели с помощью программного кода см. в разделе Navigating and Updating a Model in Program Code.
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);
} } }
Настройка средств подключения
Как правило, средство элемента создается при создании нового класса соединителя. Кроме того, можно переопределить одно средство, разрешив типам и обеих сторон определять тип отношения. Например, можно определить одно средство подключения, которое может создавать как отношения типа "человек — человек", так и отношения типа "человек — город".
Средства подключения вызывают построители подключения. Используйте построители подключения, чтобы указать, каким образом пользователи могут связывать элементы в сгенерированном конструкторе. Построители подключений указывают элементы, которые могут быть связаны, а также создаваемый между ними тип связи.
При создании ссылочного отношения между доменными классами автоматически создается построитель подключения, который можно использовать при сопоставлении средства подключения. Дополнительные сведения о создании средств подключения см. в разделе Настройка элементов и панели элементов.
Построитель подключения по умолчанию можно изменить так, чтобы он мог справляться с другим диапазоном исходных и целевых типов, а также создавать различные типы отношений.
Также, для построителей подключения можно написать пользовательский код, чтобы указать исходные и целевые классы для подключения, определить тип создаваемого подключения, и выполнить другие действия, связанные с созданием подключения.
Структура построителей подключения
Построители подключений содержат одну или несколько директив подключения связей, которые определяют доменные связи, а также исходные и целевые элементы. Например, в шаблоне решения Flow Task в Обозревателе DSL присутствует построитель подключение CommentReferencesSubjectsBuilder. Он содержит одну директиву подключения связи с именем CommentReferencesSubjects, сопоставленную с доменной связью CommentReferencesSubjects. Эта директива подключения связи содержит директиву исходной роли, указывающую на класс домена Comment, и директиву целевой роли, указывающую на класс домена FlowElement.
Использование построителей подключений для ограничения ограниченным исходных и целевых ролей
Построители подключений можно использовать для ограничения вхождения некоторых классов в исходную или в целевую роль определенной доменной связи. Например, у вас есть базовый класс домена, имеющий доменную связь с другим классом домена, но вы не хотите, чтобы все производные этого базового класса получали в этой связи те же самые роли. В решении Flow Task есть четыре конкретных класса доменов (StartPoint, EndPoint, MergeBranch и Synchronization), которые наследуются из абстрактного класса домена FlowElement напрямую, и два конкретных доменных класса (Task и ObjectInState), которые наследуются из него опосредованно. Существует также ссылочное отношение Flow, которое принимает классы доменов FlowElement как в исходной, так и в целевой роли. При этом экземпляр класса домена EndPoint не должен быть источником, а экземпляр класса StartPoint — целевым объектом экземпляра отношения Flow. Построитель подключений FlowBuilder имеет директиву подключения связи с именем Flow, которая определяет, какие классы доменов могут играть роль источника (Task, MergeBranch, StartPoint и Synchronization), а какие — роль целевого объекта (MergeBranch, Endpoint и Synchronization).
Построители подключений с несколькими директивами подключения связи
К построителю подключений можно добавить несколько директив подключения связи. Это позволяет скрыть от пользователей некоторые сложности модели домена и предотвратить чрезмерное загромождение Панели элементов. К одному построителю подключений можно добавить директивы подключения связи для нескольких различных отношений домена. При этом доменные связи следует объединять в том случае, если они выполняют примерно одинаковую функцию.
В решении Flow Task средство подключения Flow используется для протягивания экземпляров доменных связей Flow и ObjectFlow. Построитель подключения FlowBuilder в дополнение к ранее описанной директиве подключения связи Flow имеет две директивы подключения связи с именем ObjectFlow. Эти директивы указывают, что экземпляр отношения ObjectFlow может быть протянут между экземплярами класса домена ObjectInState или между экземпляром ObjectInState и экземпляром Task, но не между двумя экземплярами Task или между экземпляром Task и экземпляром ObjectInState. В то же время экземпляр отношения Flow может быть протянут между двумя экземплярами Task. Если скомпилировать и запустить решение Flow Task, можно увидеть, что протягивание Flow от экземпляра ObjectInState к экземпляру Task создает экземпляр ObjectFlow, а протягивание Flow между двумя экземплярами Task — экземпляр Flow.
Пользовательский код для построителей подключения
В пользовательском интерфейсе имеются четыре флажка, определяющие различные типы настройки построителей подключений:
– флажок Настраиваемое принятие в директиве исходной или целевой роли;
– флажок Настраиваемое подключение в директиве исходной или целевой роли;
– флажок Использует настраиваемое подключение в директиве подключения;
– свойство Является настраиваемым построителя подключений.
Чтобы указать эти настройки, необходимо предоставить определенный программный код. Чтобы узнать, какой код необходимо предоставить, установите один их этих флажков, нажмите кнопку "Преобразовать все шаблоны" и постройте собственное решение. В результате будет получено сообщение об ошибке. Дважды щелкните сообщение об ошибке, чтобы увидеть комментарий с описанием кода, который необходимо добавить.
Примечание
Чтобы добавить пользовательский код, создайте определение разделяемого класса в файле кода отдельно от файлов кода, находящихся в папках GeneratedCode.Чтобы не потерять свою работу, не изменяйте созданные файлы кода.Для получения дополнительной информации см. Overriding and Extending the Generated Classes.
Создание пользовательского кода подключения
В каждой директиве подключения связи вкладка Директивы исходной роли определяет типы, из которых можно перетаскивать код. Вкладка Директивы целевой роли определяет типы, из которых можно перетаскивать код. Для каждого типа можно дополнительно указать, разрешается ли подключение для этой директивы подключения связи. Для этого установите флажок Настраиваемое принятие и предоставьте дополнительный код.
Также можно настроить действия, происходящие после выполнения подключения. Например, можно настроить только случай перетаскивания в определенный класс, все случаи, когда приоритетное значение имеет одна директива подключения связи, или весь построитель подключения FlowBuilder. Для каждого из этих вариантов можно установить пользовательские флажки на соответствующем уровне. При преобразовании всех шаблонов и попытке построить решение вы получите сообщения об ошибках с комментариями к созданному коду. В этих комментариях указывается, что необходимо предоставить.
В примере "Схема компонентов" построитель подключения для доменной связи "Подключение" ограничивает подключения, которые могут быть установлены между портами. На следующей иллюстрации показано, что подключения можно установить только от элементов OutPort к элементам InPort, но компоненты можно вкладывать друг в друга.
Подключение входит в тип OutPort вложенного компонента
В связи с этим необходимо указать, что подключение может идти от вложенного компонента к типу OutPort. Для этого в окне Подробные сведения о DSL установите флажок Использует настраиваемое принятие в качестве исходной роли в типе InPort и в качестве целевой роли в типе OutPort, как показано на следующей иллюстрации:
Директива подключения связи в Обозревателе DSL
Директива подключения связи в окне "Подробные сведения о DSL"
После этого в класс ConnectionBuilder необходимо предоставить методы:
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…
Дополнительные сведения о настройке модели с помощью программного кода см. в разделе Navigating and Updating a Model in Program Code.
Подобный код можно использовать, например, для того, чтобы запретить пользователям создавать циклы со связями между родительскими и дочерними объектами. Эти ограничения считаются жесткими, потому что пользователи не смогут их нарушать. Можно создавать мягкие проверки достоверности, которые пользователи смогут временно обходить, создавая недопустимые конфигурации без возможности сохранения.
Рекомендации по определению построителей подключений
Чтобы создаваемые типы отношений были концептуально связаны, настраивайте только один построитель подключений. В примере с задачей потока (Task Flow) для создания потоков между задачами, а также между задачами и объектами используется один и тот же построитель. В то же время использование одного и того же построителя для создания отношений между комментариями и задачами может создавать путаницу.
Определяя построитель подключений для нескольких типов отношений, обязательно убедитесь, что он не может сопоставить больше одного типа из одной той же пары исходных и целевых объектов. В противном случае результаты будут непредсказуемы.
Пользовательский код используется для применения жестких ограничений. Подумайте, не стоит ли разрешить пользователям временное создание недопустимых подключений. Если такую возможность необходимо предоставить, ограничения можно изменить таким образом, чтобы эти подключения не проверялись до тех пор, пока пользователи не попытаются сохранить изменения.
См. также
Основные понятия
Customizing Element Creation and Movement
Практическое руководство. Добавление обработчика перетаскивания
Navigating and Updating a Model in Program Code