Начало работы

Revit API для начинающих: первый инструмент на C# без опыта программирования

Revit API — это программный интерфейс Autodesk Revit, через который внешний код читает и изменяет модель. Первый инструмент — это надстройка на C# с одной командой. Разберём её по частям: точка входа, манифест, транзакция, поток Revit — и покажем, как собрать и запустить такой плагин без опыта программирования.

Олег Сахаров·

Что такое Revit API

Revit API — программный интерфейс Autodesk Revit: набор библиотек .NET, через которые внешний код обращается к модели. Всё, что вы делаете руками в интерфейсе — выделяете элементы категории, меняете параметр, создаёте вид, готовите лист, — можно выразить в коде. Надстройка не заменяет Revit и не работает в стороне: она загружается внутрь запущенного Revit и исполняется в том же процессе, что и сама программа.

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

Отдельный язык учить не нужно: код надстройки пишут на C# (реже на VB.NET), а Revit загружает результат компиляции — DLL-сборку. Это значит, что инструменты для Revit используют те же библиотеки, отладчик и сборщик, что и любое другое приложение на .NET.

  • Читать и фильтровать элементы модели по категории, типу и значению параметра.
  • Изменять параметры и свойства элементов в рамках транзакции.
  • Создавать и размещать элементы, работать с системами и семействами.
  • Получать данные для отчётов и выгружать их во внешние форматы.
  • Добавлять свои кнопки, панели и окна в интерфейс Revit.

Документ, элементы и параметры

Чтобы код перестал быть для вас набором символов, полезно разложить модель на три уровня, с которыми работает Revit API. Верхний уровень — документ Document: это открытый файл проекта, который содержит всё остальное. Именно из документа берутся элементы и в него записываются изменения.

Средний уровень — элементы Element. Элементом является всё, что существует в модели: стена, колонна, помещение, вид, лист, уровень. У каждого элемента есть категория Category — стены, двери, окна, оборудование, — и именно по категории удобнее всего отбирать элементы.

Нижний уровень — параметры Parameter. Через них элемент несёт свои данные: длину, материал, марку, комментарий, пользовательские атрибуты. Почти любая инженерная проверка сводится к чтению параметров у отобранных элементов и сравнению значений с правилом.

Дополнительно стоит различать экземпляр и тип. Экземпляр — конкретный элемент в модели, тип — общее описание, которое он использует. Часть параметров принадлежит экземпляру, часть — типу; когда код меняет «не тот» параметр, изменение либо не сохраняется, либо затрагивает сразу все элементы типа. Это одна из самых частых причин неожиданного поведения у новичков.

Точка входа: интерфейс IExternalCommand

Внешняя команда Revit реализует интерфейс IExternalCommand. Revit находит ваш класс по манифесту, создаёт экземпляр и вызывает единственный метод Execute. Ниже — полная сигнатура этого интерфейса, ровно так, как её ожидает Revit.

public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)

Первый параметр, commandData, даёт доступ к приложению Revit, к его интерфейсу и к активному документу. Через него команда получает направления. commandData.Application.ActiveUIDocument — это точка входа к текущему файлу, который пользователь открыл в данный момент.

Второй параметр — строка message, передаваемая по ссылке. Если команда не смогла выполниться, в неё можно записать текст, и Revit покажет его пользователю. Третий параметр, ElementSet elements, — набор элементов, которые Revit подсветит при сообщении об ошибке. Это удобно, когда команда отбраковывает конкретные элементы: пользователь сразу видит, о чём речь.

Возвращаемое значение типа Result сообщает Revit итог работы:

  • Succeeded — команда отработала, ошибок нет.
  • Failed — команда не выполнена; Revit покажет текст из message.
  • Cancelled — тихий отказ без сообщения, когда отмена штатна.

Класс, в котором живёт этот метод, должен быть публичным и иметь конструктор без параметров: Revit создаёт объект сам и не знает, какие аргументы вы хотели бы передать. Поэтому все данные команда получает из окружения, а не из конструктора.

Первый код: команда читает документ

Начнём с самой безопасной операции — чтения. Команда ниже не меняет модель, а только собирает элементы нужной категории и выводит их количество. Такой каркас покажет, что надстройка загружается и видит документ, ещё до того, как вы возьмётесь за изменения.

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace FirstTool
{
    [Transaction(TransactionMode.Manual)]
    public class CountWallsCommand : IExternalCommand
    {
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIDocument uidoc = commandData.Application.ActiveUIDocument;
            Document doc = uidoc.Document;

            FilteredElementCollector collector =
                new FilteredElementCollector(doc)
                    .OfCategory(BuiltInCategory.OST_Walls)
                    .WhereElementIsNotElementType();

            int count = collector.GetElementCount();
            TaskDialog.Show("Первый инструмент", $"Стен в модели: {count}");

            return Result.Succeeded;
        }
    }
}

Разберём по строкам, потому что здесь помещается почти вся механика надстройки. Директива using подключает пространства имён Revit API: атрибуты, работу с документом и пользовательский интерфейс. Атрибут [Transaction(TransactionMode.Manual)] объявляет, что команда сама управляет транзакциями, — этим мы займёмся дальше.

Класс CountWallsCommand реализует интерфейс команды. Внутри метода мы получаем активный документ через UIDocument, а затем создаём FilteredElementCollector. Это основной инструмент чтения: коллектор проходит по модели и возвращает элементы, подходящие под фильтр. Мы ограничиваем выборку категорией стен и отбрасываем типы стен, оставляя только экземпляры.

Метод GetElementCount возвращает число найденных элементов, а TaskDialog.Show выводит его в окне поверх Revit. В конце команда возвращает Result.Succeeded. Никакой транзакции здесь нет — и не нужно: чтение модель не меняет.

Пять понятий, которых достаточно для первого понимания: пространства имён Autodesk.Revit.*, атрибут транзакции, класс команды, метод Execute и коллектор элементов. Большинство инструментов для Revit — это комбинации этих пяти частей.

Манифест .addin: как Revit узнаёт о команде

Revit не сканирует произвольные папки в поисках кода. Он читает файлы с расширением .addin из каталога %PROGRAMDATA%\Autodesk\Revit\Addins\<версия>, где в конце пути стоит номер версии Revit. Именно этот файл связывает класс в вашей сборке с кнопкой в интерфейсе.

<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
  <AddIn Type="Command">
    <Name>Первый инструмент</Name>
    <Assembly>FirstTool.dll</Assembly>
    <FullClassName>FirstTool.CountWallsCommand</FullClassName>
    <ClientId>00000000-0000-0000-0000-000000000000</ClientId>
    <VendorId>MY</VendorId>
    <VendorDescription>Первый инструмент для Revit</VendorDescription>
  </AddIn>
</RevitAddIns>

В манифесте указаны сборка, полное имя класса вместе с пространством имён и текст кнопки. Revit читает его при запуске и подгружает команду. Если сборка лежит рядом с манифестом, путь можно не указывать; если нет — путь задаётся явно.

Версия в пути — это основная версия Revit. Манифест для 2022 года лежит в папке ...\Addins\2022, для 2025 — в соответствующей. Сборка и манифест должны соответствовать версии Revit: плагин, собранный под одну версию, не загрузится в другую без пересборки, потому что у версий различается целевая среда исполнения.

Транзакции: изменение модели

Чтение модели можно делать без транзакции, изменение — нельзя. Любая операция, меняющая документ, должна быть обёрнута в транзакцию, иначе Revit отклонит вызов исключением. Транзакция — это не формальность, а гарантия целостности: либо все изменения внутри блока применяются, либо откатываются целиком.

using (Transaction t = new Transaction(doc, "Правка параметра"))
{
    t.Start();

    parameter.Set("Новое значение");

    t.Commit();
}

Здесь всё явно: транзакция открывается методом Start, изменения вносятся между началом и завершением, а Commit фиксирует результат. Если внутри блока возникнет исключение, транзакция не фиксируется, и модель останется прежней. Так неудачная команда не оставляет документ в половинчатом состоянии.

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

Однопоточность и поток Revit

Revit API однопоточный. Модель можно трогать только из того потока, в котором работает интерфейс Revit. Попытка обратиться к документу из фонового потока приводит к исключению или к непредсказуемому поведению. Это первое правило, которое отличает надстройку для Revit от обычного приложения .NET.

Отсюда следует практический вывод: если команда приходит не из кнопки в Revit, а извне — из HTTP-сервера, таймера или AI-клиента, — её нельзя выполнить прямо в момент поступления. Запрос нужно передать на поток Revit. Стандартный способ это сделать — внешнее событие ExternalEvent или событие простоя Idling: вы ставите задачу в очередь и регистрируете обработчик, а Revit вызывает его в безопасный момент.

ExternalEvent externalEvent =
    ExternalEvent.Create(new MyEventHandler());

externalEvent.Raise();

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

Версии Revit и целевая среда

Надстройки для Revit 2022–2024 собираются под .NET Framework 4.8, а для Revit 2025 и новее — под .NET 8. Это не рекомендация, а требование платформы: Revit загружает вашу сборку в свой процесс, и её среда исполнения должна совпадать. Сборка под .NET Framework 4.8 не загрузится в Revit 2025, и наоборот.

Если один инструмент должен работать на нескольких версиях, есть два пути: вести отдельные конфигурации сборки под каждую целевую среду или изолировать различия Revit API в тонком слое совместимости и держать общий код независимым от версии. В проекте RevitAiTools используется второй путь: версии 2022–2027 обслуживаются из одного исходного кода через слой совместимости. Разбор диапазона версий — на странице поддерживаемые версии Revit.

Практический вывод для новичка: определите целевую версию Revit до того, как писать код. От неё зависит и целевая среда исполнения, и часть сигнатур API, которые менялись между версиями.

Как собрать и запустить надстройку

Порядок действий короткий, но требует внимательности: один пропущенный шаг — и команда не появится.

  • Скомпилировать сборку под целевую версию Revit и её среду исполнения.
  • Положить DLL и файл .addin в каталог надстроек нужной версии.
  • Убедиться, что в манифесте верно указаны имя сборки и полное имя класса.
  • Запустить Revit и вызывать команду с панели надстроек.
  • Для отладки прикрепить отладчик к процессу Revit и поставить точку останова в методе Execute.

Отладка мало отличается от обычного .NET: вы прикрепляете отладчик к запущенному Revit и останавливаетесь в своём коде. Основная сложность — модель живёт в том же процессе, что и отладчик, поэтому ошибки нужно читать внимательно: обычное исключение внутри транзакции откатывает изменения, и симптом может выглядеть неочевидно. Сообщение из message и стек вызовов обычно дают ответ быстрее, чем повторный запуск вслепую.

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

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

Можно ли начать без опыта программирования

Да, при определённой дисциплине. C# читается как структурированный текст, а первый инструмент — это десятки строк, а не тысячи. Важно не столько писать код с нуля, сколько понимать, что именно делает каждая часть и как проверить результат на модели.

Здесь меняется роль AI-агента. Он пишет черновик по вашему описанию, объясняет строки, предлагает проверки и помогает собрать проект. От человека остаётся то, что агент сделать не может: поставить задачу, разложить её на шаги, понять модель данных Revit и принять результат. Правило простое: агент предлагает — вы проверяете на реальном файле.

  • Понимать, что такое категория, тип и экземпляр, — без этого задача ставится приблизительно.
  • Читать сообщения об ошибках и сопоставлять их со строкой кода.
  • Проверять результат руками: запустить команду и посмотреть на модель.
  • Идти от маленькой команды к составной, а не начинать с большого инструмента.

Именно так построено обучение в проекте: от первого метода Execute к составным инструментам, с использованием MCP, чтобы AI-клиент вызывал ваши команды. Состав доступа и материалы описаны на странице RevitAiTools.

Частые ошибки новичка

Большинство первых сбоев объясняется небольшим набором причин. Ниже — те, что встречаются чаще всего.

  • Изменение модели без транзакции — Revit выбрасывает исключение.
  • Обращение к документу из фонового потока вместо потока Revit.
  • Работа с ссылками на удалённые элементы: элемент перестал существовать, а код продолжает к нему обращаться.
  • Несовпадение целевой среды сборки и версии Revit, под которую она ставится.
  • Отсутствие или неверный манифест .addin, из-за чего команда не появляется в интерфейсе.
  • Долгие вычисления внутри транзакции, из-за чего Revit «замирает».
  • Подавленные исключения внутри транзакции: ошибка не видна, а изменения молча откатываются.

Эти же пункты — удобный чек-лист перед первым запуском. Если команда не появилась в интерфейсе, сначала проверьте манифест и путь к сборке; если появилась, но завершилась ошибкой, — транзакцию и поток. Такой порядок экономит больше времени, чем перебор кода целиком.

Что дальше

У вас есть весь минимум: точка входа, чтение через коллектор, транзакция, понимание однопоточности и манифест. Следующий шаг — не усложнять, а расширять по одной части за раз: сделать фильтр точнее, добавить изменение параметра, оформить отчёт. Каждый такой шаг проверяется на реальной модели, а не на предположении.

Когда захочется, чтобы команды вызывал AI-клиент, а не пользователь из интерфейса, переходите к связке плагина и MCP-сервера. Про то, как это устроено и где проходит граница проверки перед изменением модели, читайте в материале MCP для Revit и на странице RevitAiTools.

Перейти к практике

Первоначальный платёж открывает приватный GitHub-репозиторий RevitAiTools, обучающий курс и сообщество. Условия, состав доступа и актуальная цена — на главной странице.

Посмотреть условия доступа
Revit API для начинающих: первый инструмент на C# без опыта программирования