Документация по интеграции языка визуального программирования Dynamo.
В этом руководстве рассматриваются различные аспекты размещения Dynamo в приложении, благодаря чему пользователи могут взаимодействовать с приложением с помощью средств визуального программирования.
Содержание
Введение: общий обзор этого руководства и программы Dynamo.
Настраиваемая точка входа Dynamo: создание модели Dynamo и начало работы.
Привязка и трассировка элементов: использование механизма трассировки Dynamo для привязки узлов в графе к их результатам в основном приложении.
Узлы выбора Dynamo Revit: реализация узлов, которые позволяют пользователям выбирать объекты или данные из основного приложения и передавать их в качестве входных данных для графа Dynamo.
Обзор встроенных пакетов Dynamo: сведения о том, что такое стандартная библиотека Dynamo и как использовать лежащий в ее основе механизм поставки пакетов с интеграцией.
Некоторая терминология
В этих документах мы будем использовать термины «сценарий Dynamo», «граф» и «программа» как взаимозаменяемые для обозначения кода, создаваемого пользователями в Dynamo.
https://github.com/DynamoDS/DynamoRevit/blob/master/src/DynamoRevit/DynamoRevit.cs#L534
DynamoModel
является точкой входа для приложения, которое является основой для Dynamo, и представляет собой приложение Dynamo. Модель является корневым объектом верхнего уровня, который содержит ссылки на другие важные структуры данных и объекты, составляющие приложение Dynamo и виртуальную машину DesignScript.
Объект конфигурации используется для задания общих параметров в модели DynamoModel
при ее создании.
Примеры, приведенные в этом документе, взяты из реализации DynamoRevit, представляющей собой интеграцию, в которой модель DynamoModel
размещена в Revit в качестве надстройки. (Архитектура подключаемого модуля для Revit.) Когда эта надстройка загружается, она запускает DynamoModel
, а затем отображает ее для пользователя с применением DynamoView
и DynamoViewModel
.
Dynamo — это проект .NET на языке C#. Для его использования в своем приложении у вас должна быть возможность размещения и выполнения кода .NET.
DynamoCore — это кросс-платформенный вычислительный модуль и набор основных моделей, которые могут быть собраны с помощью .NET или Mono (в будущем — .NET Core). Однако DynamoCoreWPF содержит компоненты пользовательского интерфейса Dynamo только для Windows, компиляция на других платформах не поддерживается.
Чтобы инициализировать DynamoModel
, интеграторам следует выполнить указанные ниже действия в коде основного приложения.
В настоящее время список в D4R включает только Revit\SDA\bin\ICSharpCode.AvalonEdit.dll.
Это сделано во избежание конфликтов версий библиотек между Dynamo и Revit. Например, при возникновении конфликтов AvalonEdit
функция блоков кода может быть полностью нарушена. Сообщается о наличии проблемы в Dynamo 1.1.x (https://github.com/DynamoDS/Dynamo/issues/7130), которую также можно воспроизвести вручную. При обнаружении конфликтов библиотек между основной функцией и Dynamo интеграторам рекомендуется выполнить это в качестве первого шага. Иногда это необходимо для того, чтобы остановить загрузку несовместимой версии общей зависимости другим подключаемым модулем или самим основным приложением. Лучшим решением является разрешить конфликт версий путем согласования версии или использования перенаправления привязки .NET в файле app.config основного приложения, если это возможно.
ASM — это библиотека геометрии ADSK, на основе которой создана программа Dynamo.
LibG — это удобная в использовании оболочка .NET для ядра геометрии ASM. LibG использует общую схему управления версиями с ASM — она использует один и тот же основной и дополнительный номера версии ASM, чтобы указать, что она является соответствующей оболочкой определенной версии ASM. Если задана версия ASM, соответствующая версия LibG должна быть такой же. В большинстве случаев LibG должна работать со всеми версиями ASM определенной основной версии. Например, LibG 223 должна иметь возможность загрузки любой версии ASM 223.
Dynamo Sandbox позволяет работать с несколькими версиями ASM. Для этого вместе с ядром поставляются несколько версий LibG. В Dynamo Shape Manager имеется встроенная функция для поиска программ Autodesk, поставляемых вместе с ASM, поэтому Dynamo может загружать ASM из этих программ и обеспечивать работу узлов геометрии без явной загрузки в основное приложение. Список программ в том виде, в котором он существует на сегодняшний день:
Dynamo выполнит поиск в реестре Windows и выяснит, установлены ли программы Autodesk из списка на компьютере пользователя (если какие-либо из этих программ установлены), выполнит поиск двоичных файлов ASM, а также получит версию и выполнит поиск соответствующей версии LibG в Dynamo.
Учитывая версию ASM, следующий API ShapeManager выберет соответствующую папку для предварительного загрузчика LibG. Если есть точное совпадение версии, она будет использоваться, в противном случае будет загружена ближайшая версия LibG меньшего номера, но с той же основной версией.
Например, если программа Dynamo интегрирована со сборкой Revit для разработки, когда имеется более поздняя сборка ASM (225.3.0), Dynamo попытается использовать библиотеку LibG 225.3.0, если она существует, в противном случае будет предпринята попытка использовать ближайшую основную версию, номер которой меньше первой (например, 225.0.0).
public static string GetLibGPreloaderLocation(Version asmVersion, string dynRootFolder)
Revit является первой записью в списке поиска программ ASM. Это означает, что по умолчанию DynamoSandbox.exe
сначала попытается загрузить ASM из Revit, но все равно потребуется убедиться в том, что интегрированный рабочий сеанс D4R загружает ASM из текущего основного приложения Revit. Например, если на компьютере пользователя установлены и R2018, и R2020, то при запуске D4R из R2020 программа D4R должна использовать ASM 225 из R2020 вместо ASM 223 из R2018. Интеграторам потребуется реализовать вызовы, аналогичные следующим, чтобы принудительно загрузить указанную версию.
Недавно мы добавили для DynamoSandbox.exe
и DynamoCLI.exe
возможность загрузки определенной версии ASM. Чтобы пропустить обычный процесс поиска в реестре, можно использовать флаг �gp
, чтобы принудительно загрузить ASM Dynamo по определенному пути.
DynamoSandbox.exe -gp �somePath/To/ASMDirectory/�
Элемент StartupConfiguration используется для передачи в качестве параметра для инициализации DynamoModel. Это указывает на то, что он содержит почти все определения того, как следует настроить параметры сеанса Dynamo. В зависимости от того, как заданы указанные далее свойства, интеграция Dynamo может отличаться у разных интеграторов. Например, разные интеграторы могут задавать разные пути к шаблонам Python или отображаемые числовые форматы.
Элемент состоит из следующего:
DynamoCorePath // Путь к загружаемым двоичным файлам DynamoCore.
DynamoHostPath // Путь к двоичным файлам интеграции Dynamo.
GeometryFactoryPath // Путь к загруженным двоичным файлам библиотеки.
PathResolver // Объект, помогающий работать с различными файлами.
PreloadLibraryPaths // Путь к двоичным файлам предварительно загруженных узлов, например DSOffice.dll.
AdditionalNodeDirectories // Путь к дополнительным двоичным файлам узлов.
AdditionalResolutionPaths // Дополнительные пути разрешения сборок для других зависимостей, которые могут потребоваться при загрузке библиотек.
UserDataRootFolder // Папка с пользовательскими данными, например "AppData\Roaming\Dynamo\Dynamo Revit"
.
CommonDataRootFolder // Папка по умолчанию для сохранения пользовательских определений, образцов и т. д.
Context // Имя основного приложения интегратора и версия (Revit<BuildNum>)
.
SchedulerThread // Поток планировщика интегратора, реализующий ISchedulerThread
— для большинства интеграторов это основной поток пользовательского интерфейса или любой другой поток, из которого они могут получить доступ к своим API.
StartInTestMode // Указание того, является ли текущий сеанс сеансом автоматизации тестирования; изменяет ряд поведений Dynamo. Не используйте, если вы не пишете тесты.
AuthProvider // Реализация IAuthProvider, созданная интегратором, например, реализация RevitOxygenProvider находится в библиотеке Greg.dll. Используется для интеграции загрузки packageManager.
Путь настроек по умолчанию определяется параметром PathManager.PreferenceFilePath
, например "AppData\\Roaming\\Dynamo\\Dynamo Revit\\2.5\\DynamoSettings.xml"
. Интеграторы могут решить, следует ли также отправлять пользовательский файл настроек в папку, которая должна быть согласована с диспетчером путей. Далее приводятся сериализованные свойства настроек.
IsFirstRun // Указывает, запускается ли данная версия Dynamo впервые. Например, используется для определения необходимости отображения сообщения GA Opt-in/out. Также используется для определения необходимости переноса предыдущих настроек Dynamo при запуске новой версии Dynamo, чтобы обеспечить единообразный пользовательский интерфейс.
IsUsageReportingApproved // Указывает, утверждены ли отчеты об использовании.
IsAnalyticsReportingApproved // Указывает, утверждена ли аналитическая отчетность.
LibraryWidth // Ширина левой панели библиотеки Dynamo.
ConsoleHeight // Высота отображения консоли.
ShowPreviewBubbles // Указывает, должны ли отображаться выноски предварительного просмотра.
ShowConnector // Указывает, отображаются ли соединители.
ConnectorType // Указывает на тип соединителя: Безье или полилиния.
BackgroundPreviews // Указывает на активное состояние заданного фонового просмотра.
RenderPrecision // Уровень точности визуализации — более низкий уровень приводит к созданию сети с меньшим количеством треугольников. При выборе более высокого уровня создается более сглаженная геометрия в фоновом просмотре. 128 — оптимальное значение для быстрого предварительного просмотра геометрии.
ShowEdges // Указывает, будут ли визуализироваться ребра поверхностей и тел.
ShowDetailedLayout // НЕ ИСПОЛЬЗУЕТСЯ.
WindowX, WindowY // Последняя координата X, Y окна Dynamo.
WindowW, WindowH // Последнее значение ширины и высоты окна Dynamo.
UseHardwareAcceleration // Указывает, следует ли программе Dynamo использовать аппаратное ускорение, если оно поддерживается.
NumberFormat // Десятичная точность, используемая для отображения чисел в окне предварительного просмотра toString().
MaxNumRecentFiles // Максимальное количество недавних путей к файлам для сохранения.
RecentFiles // Список путей к недавно открытым файлам; изменение этого параметра напрямую повлияет на список последних файлов на начальной странице Dynamo.
BackupFiles // Список путей к файлам резервных копий.
CustomPackageFolders // Список папок, содержащих двоичные файлы Zero-Touch, и пути к каталогам, которые будут проверены на наличие пакетов и пользовательских узлов.
PackageDirectoriesToUninstall // Список пакетов, используемый диспетчером пакетов для определения пакетов, отмеченных для удаления. При запуске Dynamo эти пути будут удалены, если это возможно.
PythonTemplateFilePath // Путь к файлу Python (.py) для использования в качестве начального шаблона при создании узла PythonScript. Его можно использовать, чтобы настроить пользовательский шаблон Python для интеграции.
BackupInterval // Указывает периодичность (в миллисекундах) автоматического сохранения графа.
BackupFilesCount // Указывает, сколько резервных копий будет создано.
PackageDownloadTouAccepted // Указывает, принял ли пользователь Условия использования для скачивания пакетов из диспетчера пакетов.
OpenFileInManualExecutionMode // Указывает состояние флажка «Открыть в режиме ручного выполнения» по умолчанию в диалоговом окне OpenFileDialog.
NamespacesToExcludeFromLibrary // Указывает, какие пространства имен (если таковые имеются) не должны отображаться в библиотеке узлов Dynamo. Строковый формат: "[имя библиотеки]:[полное пространство имен]".
Пример сериализованных настроек параметров:
Extensions // Список расширений, реализующих IExtension; если он пуст, Dynamo будет загружать расширения из папки по умолчанию (папка extensions
в папке Dynamo).
IsHeadless // Указывает, запускается ли Dynamo без пользовательского интерфейса (влияет на аналитику).
UpdateManager // Реализация UpdateManager, созданная интегратором (см. описание выше).
ProcessMode // Эквивалент TaskProcessMode. При работе в тестовом режиме используется значение Synchronous, в противном случае — Asynchronous; управляет поведением планировщика. В однопоточных средах этот параметр также можно установить как Synchronous.
Используйте целевой элемент StartConfiguration для запуска DynamoModel
.
После передачи StartConfig для запуска DynamoModel
программа DynamoCore проследит за фактическими особенностями, чтобы убедиться в правильности инициализации сеанса Dynamo в соответствии с заданными параметрами. После инициализации DynamoModel
отдельным интеграторам потребуется выполнить дополнительные действия. Например, в D4R выполняется подписка на события для наблюдения за операциями основного приложения Revit или обновлениями документов, настройкой узла Python и т. д.
Чтобы инициализировать DynamoViewModel
и DynamoView
, необходимо сначала создать DynamoViewModel
, что можно сделать с помощью статического метода DynamoViewModel.Start
. См. ниже:
В DynamoViewModel.StartConfiguration
гораздо меньше параметров, чем в конфигурации модели. Параметры в основном говорят сами за себя — параметр CommandFilePath
можно игнорировать, если вы не пишете тестовый пример.
Параметр Watch3DViewModel
определяет способ отображения 3D-геометрии в узлах фонового просмотра и Watch3D. Можно использовать собственную реализацию, если вы реализуете требуемые интерфейсы.
Для построения DynamoView
требуется только DynamoViewModel
. Вид представляет собой элемент управления окна и может отображаться с помощью WPF.
DynamoSandbox.exe — это среда разработки, предназначенная для выполнения тестов, работы и проведения экспериментов в DynamoCore. Это отличный пример среды для проверки того, как загружаются и настраиваются компоненты DynamoCore
и DynamoCoreWPF
. Некоторые точки входа представлены здесь.
Трассировка — это механизм в ядре Dynamo, который позволяет сериализовать данные в файл DYN (Dynamo). Важно отметить, что эти данные привязаны к местам вызова узлов на графе Dynamo.
При открытии графа Dynamo с диска сохраненные в нем данные трассировки повторно связываются с узлами графа.
Механизм трассировки
Реализация привязки элементов в Dynamo.
Механизм трассировки можно использовать для обеспечения привязки объектов к созданной ими геометрии.
Место вызова и механизм трассировки предоставляют постоянный идентификатор GUID, который разработчик узла может использовать для повторного связывания.
Место вызова
Исполняемый файл содержит несколько мест вызова. Эти места вызова используются для диспетчеризации выполнения в различных местах, откуда они должны быть отправлены:
библиотека C#;
встроенный метод;
функция DesignScript;
пользовательский узел (функция DS).
TraceSerializer
Сериализация отмеченных классов ISerializable
и [Serializable]
в трассировку.
Выполняет сериализацию данных в трассировку и десериализацию их из нее.
TraceBinder управляет привязкой десериализованных данных к типу среды выполнения (создает экземпляр вещественного класса).
Данные трассировки сериализуются в файл DYN внутри свойства Bindings. Это массив «места вызова-идентификаторы -> данные». Место вызова — это конкретное расположение/экземпляр, в котором вызывается узел в виртуальной машине DesignScript. Следует отметить, что узлы в графе Dynamo можно вызывать несколько раз, поэтому для одного экземпляра узла может быть создано несколько мест вызова.
НЕ рекомендуется задавать зависимость от формата сериализованных данных в кодировке base64.
Существует множество причин, по которым можно сохранить произвольные данные в результате выполнения функции, но в данном случае трассировка была разработана для решения конкретной проблемы, с которой пользователи часто сталкиваются при создании и итерации программ, создающих элементы в основных приложениях.
Эту проблему мы назвали Element Binding
, и идея заключается в следующем.
При разработке и запуске графа Dynamo пользователь, скорее всего, будет создавать элементы в модели основного приложения. Рассмотрим пример: у пользователя есть небольшая программа, которая создает 100 дверей в архитектурной модели. Количество и местоположение этих дверей контролируется его программой.
При первом запуске программы пользователем создаются необходимые 100 дверей.
Позже, когда пользователь изменит входные данные в программе и выполнит их повторно, программа (без привязки элементов) создаст 100 новых дверей. При этом старые двери будут присутствовать в модели вместе с новыми.
Поскольку Dynamo представляет собой среду динамического программирования с режимом "Automatic"
(автоматически), в котором изменения графа инициируют новое выполнение, модель будет быстро заполнена результатами многочисленных выполнений программы.
Обычно это не то, чего ожидают пользователи. Вместо этого, если включить привязку элементов, предыдущие результаты выполнения графа очищаются и удаляются или изменяются. Результат (удаление или изменение) зависит от гибкости API основного приложения. Если привязка элементов включена, то после второго, третьего или 50-го выполнения программы Dynamo у пользователя в модели останется всего 100 дверей.
Для этого требуется не только сериализация данных в файл DYN. И, как вы увидите ниже, в DynamoRevit есть механизмы, созданные на основе трассировки, для поддержки рабочих процессов повторной привязки.
Сейчас самое время упомянуть еще один важный пример использования привязки элементов для основных приложений, таких как Revit. Поскольку элементы, созданные при активации привязки элементов, попытаются сохранить существующие идентификаторы элементов (изменить существующие элементы), то логика, лежащая в основе этих элементов в основном приложении, продолжит применяться после запуска программы Dynamo. Далее приводится пример.
Вернемся к примеру с архитектурной моделью.
Рассмотрим пример с отключенной привязкой элементов. На этот раз у пользователя есть программа, которая генерирует архитектурные стены.
Он запускает свою программу, и она создает стены в основном приложении. Затем пользователь выходит из графа Dynamo и с помощью обычных инструментов Revit размещает окна на стенах. Окна привязаны к этим стенам в составе модели Revit.
Пользователь запускает резервное копирование Dynamo и снова запускает граф. Теперь, как и в прошлом примере, имеется два набора стен. В первом наборе есть окна, а на новых стенах — нет.
Если была активирована привязка элементов, можно сохранить работу, выполненную вручную в основном приложении без использования Dynamo. Например, если привязка была включена при запуске программы во второй раз, стены будут изменены, а не удалены, а последующие изменения, внесенные в основном приложении, сохранятся. Модель будет содержать стены с окнами, а не два набора стен с разными состояниями.
Трассировка — это механизм в Dynamo Core, который использует статическую переменную мест вызова и данных для сопоставления данных с местом вызова функции в графе, как описано выше.
Кроме того, она позволяет сериализовать произвольные данные в файл DYN при записи узлов Dynamo Zero Touch. Обычно это не рекомендуется, поскольку это означает, что потенциально переносимый код Zero Touch теперь зависит от ядра Dynamo.
Не полагайтесь на сериализованный формат данных в файле DYN. Вместо этого используйте атрибут [Serializable] и интерфейс.
Компонент ElementBinding, напротив, является надстройкой на основе API трассировки и реализован в интеграции Dynamo (DynamoRevit, Dynamo4Civil и т. д.).
Некоторые из низкоуровневых API трассировки, о которых стоит знать:
Можно увидеть их использование в примере ниже.
Для взаимодействия с данными трассировки, загруженными или создаваемыми Dynamo из существующего файла, можно обратиться к следующим методам:
Пример узла Dynamo, который использует трассировку напрямую, находится в репозитории DynamoSamples.
В описании класса объясняется суть того, что такое трассировка:
В этом примере API трассировки непосредственно в DynamoCore используется для сохранения некоторых данных при выполнении определенного узла. В этом случае словарь играет роль модели основного приложения — подобно базе данных модели Revit.
Примерная настройка:
В качестве узла в Dynamo импортируется статический утилитарный класс TraceExampleWrapper
. Он содержит один метод, ByString
, который создает TraceExampleItem
. Это обычные объекты .NET, содержащие свойство description
.
Каждый элемент TraceExampleItem
сериализуется в трассировку, представленную в виде TraceableId
. Это просто класс, содержащий IntId
, который помечен как [Serializeable]
, чтобы его можно было сериализовать с помощью средства форматирования SOAP
. Дополнительные сведения о серализуемом атрибуте см. здесь.
Кроме того, необходимо реализовать интерфейс ISerializable
, определенный здесь.
Этот класс создается для каждого элемента TraceExampleItem
, который требуется сохранить в трассировке, сериализовать, закодировать с помощью кодировки base64 и сохранить на диск при сохранении графа, чтобы можно было повторно сопоставить привязки, даже позже, когда граф снова откроется поверх существующего словаря элементов. В данном примере это не сработает, поскольку словарь на самом деле не является постоянным, как документ Revit.
Наконец, последняя часть уравнения — это TraceableObjectManager
, которая аналогична ElementBinder
в DynamoRevit
. Она управляет взаимосвязью между объектами, присутствующими в модели документа основного приложения, и данными, сохраненными в трассировке Dynamo.
При первом запуске графа, содержащего узел TraceExampleWrapper.ByString
, создается TraceableId
с новым идентификатором, TraceExampleItem
сохраняется в словаре, сопоставленном с этим новым идентификатором, а TraceableID
сохраняется в трассировке.
При следующем запуске графа обращаемся к трассировке, находим сохраненный там идентификатор, находим объект, сопоставленный с этим идентификатором, и возвращаем этот объект. Вместо создания нового объекта мы изменяем существующий.
Поток из двух последовательных выполнений графа, который создает один элемент TraceExampleItem
, выглядит следующим образом:
Эта же идея демонстрируется в следующем более реалистичном примере использования узла DynamoRevit.
В последних версиях Dynamo использование TLS (локального хранилища потока) заменено на статическое использование элементов.
Давайте коротко рассмотрим, как выглядит узел, использующий привязку элементов, при реализации в DynamoRevit. Он аналогичен типу узла, который использовался выше в примерах создания стен.
Приведенный выше код иллюстрирует пример конструктора для элемента стены. Этот конструктор вызывается из узла Dynamo, такого как Wall.byParams
.
При выполнении конструктора важно соблюдать следующие рекомендации, так как они относятся к привязке элементов.
Используйте elementBinder
, чтобы проверить, есть ли ранее созданные объекты, которые были привязаны к этому месту вызова во время прошлого запуска. ElementBinder.GetElementFromTrace<Autodesk.Revit.DB.Wall>
Если это так, попробуйте изменить такую стену, а не создавать новую.
В противном случае создайте новую стену.
Удалите старый элемент, который мы только что извлекли из трассировки, и добавьте новый, чтобы можно было найти этот элемент в будущем.
В настоящее время каждый объект трассировки сериализуется с использованием форматирования XML SOAP; это довольно подробно, в результате чего дублируется много информации. Затем данные дважды кодируются в кодировке base64, что неэффективно с точки зрения сериализации или десериализации. Это можно улучшить в будущем, если поверх не применяется внутренний формат. Опять же, не полагайтесь на формат хранимых сериализованных данных.
Существуют случаи, когда привязка элементов нежелательна. Что делать, если вы, будучи опытным пользователем Dynamo, разрабатываете программу, которую требуется запускать несколько раз для создания случайных элементов группировки. Целью программы является создание дополнительных элементов при каждом запуске программы. Это непросто реализовать без обходных путей, которые отключают привязку элементов. Привязку элементов можно отключить на уровне интеграции, но, скорее всего, это должно быть основной функцией Dynamo. Непонятно, насколько детализированным должен быть этот функционал: уровень узла, уровень места вызова, весь сеанс Dynamo, рабочее пространство или что-то еще?
Обычно эти узлы позволяют пользователю каким-либо образом описать подмножество активных документов Revit, на которые следует сослаться. Существуют различные способы, которыми пользователь может ссылаться на элемент Revit (описаны ниже). Результатом вывода узла может быть оболочка элемента Revit (оболочка DynamoRevit) или геометрия Dynamo (преобразованная из геометрии Revit). Различия между этими типами выходных данных будет полезно рассмотреть в контексте других интеграций основного приложения.
В общих чертах, хороший способ концептуализировать эти узлы — использовать их как функцию, которая принимает идентификатор элемента и возвращает указатель на этот элемент или какую-либо геометрию, представляющую этот элемент.
В DynamoRevit имеется несколько узлов �Selection�
. Можно разделить их как минимум на две группы.
Выбор в пользовательском интерфейсе:
Пример узлов DynamoRevit
в этой категории — SelectModelElement
, SelectElementFace
.
Эти узлы позволяют пользователю переключиться в контекст пользовательского интерфейса Revit и выбрать элемент или набор элементов, при этом запоминаются идентификаторы этих элементов, и запустить функцию преобразования. Либо создается оболочка, либо извлекается и преобразуется геометрия из элемента. Выполняемое преобразование зависит от типа узла, выбранного пользователем.
Запрос документа:
Примеры узлов в этой категории: AllElementsOfClass
, AllElementsOfCategory
.
Эти узлы позволяют пользователю запрашивать во всем документе подмножество элементов. Обычно эти узлы возвращают оболочки, указывающие на базовые элементы Revit. Эти оболочки являются неотъемлемой частью интерфейса DynamoRevit и позволяют использовать расширенные функции, такие как привязка элементов, а также позволяют интеграторам Dynamo выбирать, какие основные API будут отображаться в качестве узлов для пользователей.
Пользователь выбирает стену Revit с помощью SelectModelElement
. На графе возвращается оболочка стены Dynamo (отображается в окне предварительного просмотра узла).
Пользователь размещает узел Element.Geometry и присоединяет к нему выходные данные SelectModelElement
. Извлекается геометрия стены с огибанием, после чего она преобразуется в геометрию Dynamo с помощью API libG.
Пользователь переключает граф в режим автоматического запуска.
Пользователь изменяет исходную стену в Revit.
Граф автоматически запускается повторно, поскольку документ Revit вызвал событие, сигнализирующее об обновлении некоторых элементов. Узел выбора отслеживает это событие и проверяет, был ли изменен идентификатор выбранного элемента.
Рабочие процессы в D4C очень похожи на описанные выше для Revit. Ниже представлено два типовых набора узлов выбора в D4C.
Благодаря средству обновления изменений документа, который реализует узлы Selection в DynamoRevit
, легко создавать бесконечные циклы: представьте себе узел, который отслеживает все элементы в документе, а затем создает новые элементы где-то ниже уровня этого узла. При выполнении этой программы будет запущен цикл. DynamoRevit
пытается перехватить это различными способами, используя идентификаторы транзакций, и избегает изменения документа, если входные данные, поступившие в конструкторы элементов, не изменились.
Это необходимо учитывать, если автоматическое выполнение графа запускается при изменении выбранного элемента в основном приложении.
Узлы Selection в DynamoRevit
реализованы в проектеRevitUINodes.dll
, который ссылается на WPF. Возможно, это не проблема, но о ней стоит знать, в зависимости от целевой платформы.
Узлы Selection реализуются путем наследования от общих типовSelectionBase
: SelectionBase<TSelection, TResult>
и минимального набора элементов.
Реализация метода BuildOutputAST
— этот метод должен возвращать AST, который будет выполнен в какой-то момент в будущем, когда узел должен быть выполнен. В случае с узлами Selection он должен возвращать элементы или геометрию по идентификаторам элементов. https://github.com/DynamoDS/DynamoRevit/blob/master/src/Libraries/RevitNodesUI/Selection.cs#L280
Реализация BuildOutputAST
— одна из самых сложных частей реализации узлов NodeModel
/пользовательского интерфейса. Лучше всего вложить в функцию C# как можно больше логики и просто встроить в AST узел вызова функции AST. Обратите внимание, что в данном случае node
является узлом AST в абстрактном дереве синтаксиса, а не узлом в графе Dynamo.
Сериализация
Поскольку это явные производные типы NodeModel
(не ZeroTouch), для них также необходимо реализовать компонент [JsonConstructor], который будет использоваться во время десериализации узла из файла DYN.
Ссылки на элементы из основного приложения необходимо сохранить в файле DYN, чтобы при открытии пользователем графа, содержащего этот узел, его выбор оставался неизменным. Узлы NodeModel в Dynamo используют для сериализации json.net, все общие свойства будут сериализованы автоматически с помощью json.net. Используйте атрибут [JsonIgnore] для сериализации только необходимых компонентов.
Узлы Document Query немного проще, так как им не нужно хранить ссылки на идентификаторы элементов. См. сведения ниже о реализации класса ElementQueryBase
и производных классов. При выполнении эти узлы вызывают API Revit и запрашивают элементы в базовом документе, а также выполняют указанное выше преобразование в оболочку элементов геометрии или Revit.
Механизм встроенных пакетов — это попытка объединить больше содержимого узла с Dynamo Core без расширения самого ядра за счет использования функции загрузки пакетов Dynamo, реализованной в расширениях PackageLoader
и PackageManager
.
В этом документе используются взаимозаменяемые термины «встроенные пакеты» и «встроенные пакеты Dynamo» для обозначения одного и того же.
Пакет должен иметь подписанные двоичные точки входа, иначе он не будет загружен.
Необходимо приложить все усилия, чтобы избежать критических изменений в этих пакетах. Это означает, что содержимое пакета должно включать автоматические тесты.
Семантическое управление версиями: для управления версиями пакета оптимально использовать схему семантического управления версиями; предоставьте ее пользователям в описании пакета или документации.
Автоматизированные тесты. См. информацию выше. Если пакет включен с использованием механизма встроенного пакета, то для пользователя он выглядит как часть программы и должен быть протестирован как программа.
Высокий уровень визуального оформления: значки, документация по узлам, локализация содержимого.
Не отправляйте пакеты, обслуживание которых вы или ваша команда не в состоянии организовать.
Не отправляйте таким образом пакеты сторонних разработчиков (см. выше).
По сути, у вас должен быть полный контроль над пакетом, возможность исправить его, обновить и проверить на соответствие последним изменениям в Dynamo и программе. Кроме того, у вас должна быть возможность его подписывать.
Предполагается, что Built-In Packages
будет основной функцией, набором пакетов, к которым будут иметь доступ все пользователи, даже если у них нет доступа к диспетчеру пакетов. В настоящее время базовым механизмом поддержки этой функции является дополнительное расположение по умолчанию для загрузки пакетов непосредственно в каталог ядра Dynamo (относительно DynamoCore.dll).
С некоторыми ограничениями это расположение можно использовать для клиентов и интеграторов ADSK Dynamo в целях распространения пакетов для интеграции. (Например, для интеграции Dynamo и FormIt требуется настраиваемый пакет Dynamo FormIt.)
Поскольку базовый механизм загрузки одинаков как для основных пакетов, так и для специализированных пакетов для основного приложения, необходимо убедиться, что пакеты, распространяемые таким образом, не приводят к путанице между основными пакетами Built-In Packages
и пакетами для интеграции, которые доступны только в одной основной программе. Во избежание путаницы рекомендуется обсудить с группами разработчиков Dynamo пакеты для конкретного узла.
Поскольку пакеты, включенные в Built-In Packages
, будут доступны большему количеству клиентов, а гарантии, которые мы даем относительно них, будут более строгими (см. выше), их следует локализовать.
Для внутренних пакетов ADSK, предназначенных для включения Built-In Packages
, текущие ограничения, связанные с невозможностью публикации локализованного содержимого в диспетчере пакетов, не являются препятствием, поскольку пакеты не обязательно публиковать в диспетчере пакетов.
С помощью временного решения можно вручную создать (и даже опубликовать) пакеты со вложенными каталогами с региональными настройками в папке /bin пакета.
Сначала вручную создайте необходимые вложенные каталоги для конкретных региональных настроек в папке /bin
пакетов.
Если по какой-либо причине пакет необходимо также опубликовать в диспетчере пакетов, необходимо сначала опубликовать версию пакета, в которой отсутствуют эти вложенные каталоги с региональными настройками, а затем опубликовать новую версию пакета с помощью функции publish package version
DynamoUI. Новая версия, выгруженная в Dynamo, не должна удалять папки и файлы в папке /bin
, которые были добавлены вручную с помощью проводника Windows. Процесс выгрузки пакетов в Dynamo будет обновлен с учетом требований к локализованным файлам в будущем.
Эти вложенные каталоги с региональными настройками загружаются без проблем средой выполнения .NET, если они расположены в том же каталоге, что и двоичные файлы узла/расширения.
Дополнительные сведения о сборках ресурсов и файлах RESX см. в статье https://docs.microsoft.com/ru-ru/dotnet/framework/resources/creating-resource-files-for-desktop-apps.
Скорее всего, вы будете создавать файлы .resx
и компилировать их с помощью Visual Studio. Для заданной сборки xyz.dll
результирующие ресурсы будут скомпилированы в новую сборку xyz.resources.dll
; как описано выше, расположение и название этой сборки имеют значение.
Сгенерированный файл xyz.resources.dll
должен находиться по следующему пути: package\bin\culture\xyz.resources.dll
.
Для доступа к локализованным строкам в пакете можно использовать ResourceManager, но еще проще обратиться к Properties.Resources.YourLocalizedResourceName
из сборки, для которой добавлен файл .resx
. Пример:
https://github.com/DynamoDS/Dynamo/blob/master/src/Libraries/CoreNodes/List.cs#L457 — пример локализованного сообщения об ошибке
https://github.com/DynamoDS/Dynamo/blob/master/src/Libraries/CoreNodeModels/ColorRange.cs#L19 — пример локализованной конкретной строки атрибута NodeDescription для Dynamo
https://github.com/DynamoDS/DynamoSamples/blob/master/src/SampleLibraryUI/Examples/LocalizedCustomNodeModel.cs — другой пример
Как правило, когда Dynamo загружает узлы из пакета, они помещаются в раздел Addons
в библиотеке узлов. Для лучшей интеграции узлов встроенных пакетов с другими встроенными компонентами для разработчиков встроенных пакетов добавлена возможность предоставлять файл layout specification
частично, чтобы их можно было разместить в правильной категории верхнего уровня в разделе библиотеки default
.
Например, указанный файл JSON при обнаружении по пути package/extra/layoutspecs.json
, поместит узлы, заданные параметром path
, в категорию Revit
в разделе default
, который является основным разделом встроенных узлов.
Обратите внимание, что узлы, импортированные из встроенного пакета, будут иметь префикс bltinpkg://
, если они рассматриваются для сопоставления с путем, включенным в спецификацию компоновки.
Сложные изменения компоновки недостаточно хорошо протестированы и не поддерживаются. Цель загрузки спецификации компоновки состоит в том, чтобы переместить все пространство имен пакета в определенную категорию узла, например Revit
или Formit
.