Найти в Дзене
IT4BIM

Упрощение разработки интерфейса Revit: расширения для ленты и кнопок

При разработке плагинов для Revit неминуемо встает вопрос: как быстро и удобно создавать кнопки, вкладки и панели на ленте. Каждый раз писать одну и ту же громоздкую логику — неудобно и нечитабельно. В этой статье я покажу, как можно значительно упростить работу с интерфейсом Revit, вынеся часто повторяющийся код в переиспользуемые расширения. Эти инструменты сделают ваш код чище, удобнее для поддержки и расширения. Также я покажу, как легко подключать ресурсы с иконками и масштабировать их на лету. При разработке интерфейса для Revit часто возникает необходимость добавлять пользовательские панели (RibbonPanel) во вкладки на ленте. Однако каждый раз приходится писать похожую логику: получить вкладку, проверить, существует ли уже нужная панель, а если нет — создать её. Чтобы упростить эту рутину, мы создали расширение GetOrCreateRibbonPanel, которое автоматически возвращает нужную панель, создавая её при необходимости. Это делает код в методе OnStartup намного чище и декларативнее. Опис
Оглавление

При разработке плагинов для Revit неминуемо встает вопрос: как быстро и удобно создавать кнопки, вкладки и панели на ленте. Каждый раз писать одну и ту же громоздкую логику — неудобно и нечитабельно. В этой статье я покажу, как можно значительно упростить работу с интерфейсом Revit, вынеся часто повторяющийся код в переиспользуемые расширения.

Мы рассмотрим два вспомогательных класса:

  • RevitPanelTools — для создания панелей на ленте;
  • RevitButtonTools — для добавления кнопок, иконок и сплит-кнопок.

Эти инструменты сделают ваш код чище, удобнее для поддержки и расширения. Также я покажу, как легко подключать ресурсы с иконками и масштабировать их на лету.

🔧 Работа с панелями: RevitPanelTools

При разработке интерфейса для Revit часто возникает необходимость добавлять пользовательские панели (RibbonPanel) во вкладки на ленте. Однако каждый раз приходится писать похожую логику: получить вкладку, проверить, существует ли уже нужная панель, а если нет — создать её.

Чтобы упростить эту рутину, мы создали расширение GetOrCreateRibbonPanel, которое автоматически возвращает нужную панель, создавая её при необходимости. Это делает код в методе OnStartup намного чище и декларативнее.

📄 Метод GetOrCreateRibbonPanel

-2

🔍 Как это работает:

  1. Метод расширения
    Метод объявлен с ключевым словом this перед параметром UIControlledApplication application, что делает его расширением и позволяет вызывать его прямо на объекте application.
  2. Поиск существующей панели
    Вначале получаем все панели на вкладке tabName с помощью application.GetRibbonPanels(tabName). Затем находим первую панель с нужным именем (panelName) через FirstOrDefault(...).
  3. Создание панели, если не найдена
    Если нужная панель не найдена (результат FirstOrDefault равен null), вызывается application.CreateRibbonPanel(...), создающая новую панель с заданным именем.
  4. Параметр по умолчанию
    Значение вкладки (tabName) по умолчанию — "IT4BIM", но вы можете передать любое другое имя вкладки.

🔧 Работа с кнопками: RevitButtonTools

1. CreateButton<TCommand>

-3

Описание:
Создаёт кнопку (PushButton) и добавляет её на панель RibbonPanel.

Параметры:

  • TCommand — класс команды, реализующий IExternalCommand.
  • ribbonPanel — панель, на которую будет добавлена кнопка.
  • label — текст кнопки.
  • tooltip — всплывающая подсказка.
  • iconImageName — имя иконки из ресурсов.
  • tooltipImageName (опционально) — картинка, отображаемая в подсказке.
  • helpURL (опционально) — ссылка на справочную страницу.
  • longDescription (опционально) — расширенное описание кнопки.
  • availabilityClass (опционально) — класс, определяющий доступность кнопки.
  • smallIconImageName (опционально) — отдельная маленькая иконка 16×16. (по умолчанию сжимает изображение из переменной iconImageName)
    Изображения берутся из папки Resources, в свойствах изображения нужно указать Build Action - Resource

Как работает:
Метод формирует PushButtonData с помощью CreatePushButtonData<TCommand>, затем добавляет кнопку в RibbonPanel через AddItem.

2. CreatePushButtonData<TCommand>

-4

Описание:
Создаёт и настраивает объект PushButtonData, который описывает кнопку.

Параметры:
(Те же, что в CreateButton.)

Как работает:

  • Указывает путь к сборке и полное имя команды.
  • Загружает иконки.
  • Устанавливает подсказки, длинное описание и ссылку на помощь.
  • Устанавливает класс доступности, если он задан.
  • Масштабирует картинку для маленькой иконки, если отдельная маленькая не указана.

Особенность:
Можно использовать отдельно, чтобы потом собрать несколько кнопок в SplitButton или Stack.

3. CreateSplitButtons

-5

Описание:
Создаёт и добавляет SplitButton — это кнопка с выпадающим списком других кнопок.

Параметры:

  • ribbonPanel — панель, на которую добавляется SplitButton.
  • internalName — внутреннее имя SplitButton.
  • buttonText — текст кнопки.
  • buttonsData — массив кнопок (PushButtonData), которые будут внутри SplitButton (от 2 до 5 кнопок).

Как работает:

  • Создаёт SplitButtonData и добавляет его на панель.
  • Вставляет все переданные кнопки.
  • Назначает первую кнопку как кнопку по умолчанию (CurrentButton).

Важно:
Если передано меньше 2 или больше 5 кнопок — выбрасывается ArgumentException.

4. CreateStackedButtons

-6

Описание:
Добавляет на панель 2-3 кнопки, расположенные в одну строку.

Параметры:

  • ribbonPanel — панель для размещения.
  • button1, button2 , button3— данные для двух кнопок.

Как работает:
Вызывает AddStackedItems панели RibbonPanel, передавая обе кнопки.

💡 Пример использования:

-7

Преимущества подхода:

  • Минимум кода: Вся логика получения или создания панели — в одной строке.
  • Без дублирования: Не нужно каждый раз проверять, существует ли панель.
  • Гибкость: Можно использовать любое имя вкладки.
  • Мы можем получить уже существующую панель и добавить кнопку именно на нее из другого проекта/решения

🛠 Рекомендация: выносите создание панели в отдельный метод

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

Например, вместо того чтобы сразу в OnStartup добавлять команды и элементы управления, лучше вызвать отдельный метод, ответственный за конкретную панель.
Данная логика позволит разрабатывать плагины связанные с разными доменами в разных решениях и разных гит репозиториях. А соединять в одно корпоративное решение в другом проекте с минимумом логики – только вызовы по созданию панелей плагинов.

-8

Здесь вы уже видите структуру проектов, которую лучше разбить по разным решениям и гит репозиториям, но для удобства статьи организую в рамках одного решения

-9

Вывод

В этом примере мы разработали класс RevitButtonTools, который упрощает создание различных типов кнопок для интерфейса Revit.
Он позволяет быстро добавлять одиночные кнопки, группы из двух или трёх кнопок, а также кнопки с выпадающим списком.
Особое внимание было уделено удобной настройке внешнего вида кнопок — всплывающим подсказкам, иконкам и ссылкам на справочные материалы.

Чтобы продемонстрировать работу RevitButtonTools и других утилит, мы создали отдельный проект Bim.Examples.Library.
Этот проект мы специально вынесли в отдельную библиотеку с расчётом на последующую публикацию в виде NuGet-пакета.
Это позволит упростить повторное использование кода в реальных проектах без необходимости копировать вспомогательные классы вручную.

Также хочу отметить важный момент:
при использовании метода CreatePushButtonData рекомендуется задавать картинку по умолчанию.
Это удобно для тестовых и временных команд — кнопки будут иметь аккуратный вид даже в процессе разработки и отладки.

Что дальше?
В следующих шагах мы рассмотрим, как подготовить проект для публикации, оформить NuGet-пакет и подключить его в реальном проекте Revit.
Таким образом, мы ещё больше упростим подключение общих инструментов в разных решениях и командах.