Разработка и Конфигурация · 10 мин
1С: как обойти реквизиты формы программно
Как программно обойти реквизиты формы в 1С: ПолучитьРеквизиты, РеквизитФормыВЗначение, обход колонок таблицы значений. Примеры кода, ошибки и проверка результата.
Обход реквизитов формы — типовая задача при разработке на управляемых формах 1С: нужно перебрать все реквизиты, найти нужные по имени или типу, скопировать значения, очистить форму или проверить заполненность. Напрямую «пройтись циклом» по реквизитам формы нельзя — у объекта «УправляемаяФорма» нет коллекции реквизитов в привычном смысле. Но платформа даёт несколько рабочих механизмов, и выбор зависит от того, что именно требуется: имена, значения, типы или структура табличных частей формы.
Основной инструмент — метод формы ПолучитьРеквизиты(), который возвращает массив объектов «РеквизитФормы». У каждого элемента массива есть свойства «Имя», «Путь», «ТипЗначения» и «Заголовок», по которым и строится обход. Для работы со значениями применяют обращение через «ЭтаФорма[ИмяРеквизита]» либо преобразование «РеквизитФормыВЗначение».
Как устроены реквизиты формы и почему простой цикл не работает
На управляемой форме реквизиты — это не свойства объекта формы, а отдельная коллекция данных, описанная в дереве реквизитов формы. Обращение «ЭтаФорма.МойРеквизит» работает благодаря механизму расширения формы, но перечислить такие свойства через «Для Каждого» напрямую нельзя: коллекция не экспонируется как итерируемый объект.
Поэтому платформа предоставляет метод ПолучитьРеквизиты(). Он возвращает массив реквизитов верхнего уровня. Если передать в параметре путь к таблице (например, ПолучитьРеквизиты("Товары")), метод вернёт массив колонок этой таблицы — это ключевой приём для обхода вложенных структур.
Базовый обход через ПолучитьРеквизиты
Минимальный рабочий код обхода всех реквизитов верхнего уровня выглядит так:
РеквизитыФормы = ЭтаФорма.ПолучитьРеквизиты();
Для Каждого Реквизит Из РеквизитыФормы Цикл
ИмяРеквизита = Реквизит.Имя;
ТипРеквизита = Реквизит.ТипЗначения;
Значение = ЭтаФорма[ИмяРеквизита];
Сообщить(ИмяРеквизита + " : " + Строка(Значение));
КонецЦикла;
Здесь важно различать объект описания реквизита и само значение. «Реквизит.Имя» — строка, «Реквизит.ТипЗначения» — описание типов, а значение извлекается индексированным обращением «ЭтаФорма[Имя]». Такой приём работает и для записи: «ЭтаФорма[Имя] = НовоеЗначение» — удобно, когда имя реквизита заранее неизвестно и вычисляется динамически.
Учтите, что ПолучитьРеквизиты() без параметров вернёт только реквизиты верхнего уровня: колонки таблиц и реквизиты вложенных структур в массив не попадут. Их обход выполняется отдельным вызовом с указанием пути.
- 1Вызовите ЭтаФорма.ПолучитьРеквизиты() и сохраните массив
- 2Переберите массив циклом Для Каждого
- 3Отфильтруйте реквизиты по имени, типу или пути, если нужны не все
- 4Прочитайте значение через ЭтаФорма[Реквизит.Имя]
- 5Проверьте результат в отладчике или через Сообщить
Обход колонок таблицы значений на форме
Таблицы значений и динамические списки на форме — частый источник вопросов. Чтобы обойти колонки таблицы «Товары», передайте её имя в ПолучитьРеквизиты:
Колонки = ЭтаФорма.ПолучитьРеквизиты("Товары");
Для Каждого Колонка Из Колонки Цикл
Сообщить("Колонка: " + Колонка.Имя + ", тип: " + Колонка.ТипЗначения);
КонецЦикла;
Для обхода строк таблицы с доступом к значениям ячеек используется стандартный цикл по коллекции данных формы:
Для Каждого СтрокаТаблицы Из ЭтаФорма.Товары Цикл
Для Каждого Колонка Из Колонки Цикл
ЗначениеЯчейки = СтрокаТаблицы[Колонка.Имя];
КонецЦикла;
КонецЦикла;
Такой двойной обход полезен при универсальной выгрузке таблицы формы, проверке заполненности всех ячеек или поиске значений без жёсткой привязки к именам колонок. Помните, что обращение к строке по имени колонки работает, только если колонка существует — иначе будет ошибка выполнения.
Альтернатива: обход через РеквизитФормыВЗначение
Если на форме один основной реквизит объекта (например, «Объект» в форме документа или справочника), часто удобнее не обходить реквизиты формы, а преобразовать данные в прикладной объект: ЭтаФорма.РеквизитФормыВЗначение("Объект"). У полученного объекта уже есть метаданные, и обход реквизитов выполняется через «Метаданные().Реквизиты»:
ОбъектДанные = ЭтаФорма.РеквизитФормыВЗначение("Объект");
Для Каждого РеквизитМД Из ОбъектДанные.Метаданные().Реквизиты Цикл
Значение = ОбъектДанные[РеквизитМД.Имя];
КонецЦикла;
Этот способ даёт доступ ко всем реквизитам объекта конфигурации, включая те, что не выведены на форму. Обратная сторона — преобразование «РеквизитФормыВЗначение» создаёт копию данных и может быть ресурсоёмким на больших объектах, а изменения вернутся на форму только после «ЗначениеВРеквизитФормы».
Сравнение подходов
Подходит для обхода именно реквизитов формы, включая добавленные программно. Не показывает реквизиты объекта, скрытые от формы.
Подходит для обхода реквизитов прикладного объекта целиком. Требует основного реквизита формы и затрат на преобразование.
Подходит, когда набор реквизитов известен заранее или формируется по шаблону имён. Самый быстрый вариант.
Практические сценарии: очистка, копирование, проверка заполненности
Очистка всех реквизитов формы
Типовая задача — сбросить значения всех реквизитов, кроме служебных. В цикле проверяйте тип значения и присваивайте пустое значение соответствующего типа либо Неопределено:
Для Каждого Реквизит Из ЭтаФорма.ПолучитьРеквизиты() Цикл
Если Реквизит.Имя = "Объект" Тогда
Продолжить; // основной объект не трогаем
КонецЕсли;
ЭтаФорма[Реквизит.Имя] = Неопределено;
КонецЦикла;
Проверка заполненности без жёсткого списка
Для произвольной формы можно проверить, какие реквизиты не заполнены, используя «ЗначениеЗаполнено»:
Для Каждого Реквизит Из ЭтаФорма.ПолучитьРеквизиты() Цикл
Если Не ЗначениеЗаполнено(ЭтаФорма[Реквизит.Имя]) Тогда
Сообщить("Не заполнен реквизит: " + Реквизит.Заголовок);
КонецЕсли;
КонецЦикла;
Копирование значений между формами
При работе с двумя похожими формами (например, форма выбора параметров и форма настройки) значения переносят по совпадающим именам. Перед записью убедитесь, что реквизит с таким именем существует на форме-приёмнике — иначе обращение вызовет исключение. Надёжнее сначала собрать массив имён реквизитов приёмника и проверять вхождение.
Типичные ошибки и ограничения
Самая частая ошибка — попытка прочитать «Реквизит.Значение». У объекта «РеквизитФормы» нет такого свойства: значение хранится в данных формы и доступно только через «ЭтаФорма[Имя]». Вторая распространённая проблема — ожидание, что ПолучитьРеквизиты() вернёт колонки таблиц: без параметра пути они не возвращаются.
Также учитывайте контекст выполнения. В клиент-серверном режиме обращение «ЭтаФорма[Имя]» на клиенте работает только для реквизитов, чьи типы доступны на клиенте. Для сложных серверных типов обход выполняйте в серверной процедуре с директивой «&НаСервере».
Ещё одно ограничение: реквизиты с типом «ДинамическийСписок» нельзя перебрать как значения — их данные формируются запросом, и обходить нужно не реквизит, а результат запроса или построитель списка.
Как проверить результат обхода
После реализации обхода убедитесь, что массив реквизитов не пуст и содержит ожидаемые элементы. Проще всего вывести имена в отладчике: поставьте точку останова внутри цикла и посмотрите содержимое «Реквизит.Имя» и «Реквизит.ТипЗначения». Если массив пуст — проверьте, что код выполняется в контексте формы, а не в модуле объекта или общем модуле без передачи формы.
Для проверки записи значений сравните данные формы до и после обхода: откройте форму, выполните процедуру и визуально убедитесь, что поля изменились. Для табличных частей проверяйте количество строк и значения в нескольких строках, а не только в первой.
Как проверить результат
Содержит элементы с заполненными Имя и ТипЗначения
Пустой массив — код выполнен не в контексте формы
Возвращается значение без исключения
Ошибка «Поле объекта не обнаружено» — имени нет среди реквизитов
Поля формы обновились на экране
Изменения не видны — запись шла в копию после РеквизитФормыВЗначение без обратного преобразования
FAQ: частые вопросы об обходе реквизитов формы
Можно ли обойти реквизиты формы на обычных формах?
На обычных формах механизм другой: там доступны метаданные объекта и реквизиты через структуру формы, но метода ПолучитьРеквизиты нет. Обычно обходят реквизиты объекта через Метаданные() либо перебирают элементы управления формы. Описанные в статье приёмы относятся к управляемым формам.
Как найти реквизит формы по части имени?
Переберите массив ПолучитьРеквизиты() и используйте строковые функции: СтрНайти(Реквизит.Имя, "Префикс") или Лев()/Прав() для сравнения. Так можно собрать, например, все реквизиты с префиксом «Настройка_» и обработать их группой.
Почему в цикле не видны колонки таблицы значений?
ПолучитьРеквизиты() без параметров возвращает только реквизиты верхнего уровня. Колонки конкретной таблицы получают вызовом ПолучитьРеквизиты("ИмяТаблицы"), а затем обходят отдельным циклом.
Как обойти программно добавленные реквизиты формы?
Реквизиты, добавленные методом ИзменитьРеквизиты, попадают в тот же массив ПолучитьРеквизиты() и обходятся одинаково. Главное — выполнять обход после того, как состав реквизитов изменён, иначе новые элементы в массив не попадут.
Чем опасен обход через РеквизитФормыВЗначение в цикле?
Каждый вызов преобразования создаёт полную копию данных объекта. Если вызывать его многократно внутри цикла, производительность заметно падает. Правильный подход — выполнить преобразование один раз до цикла и работать с полученным объектом.
Можно ли обойти реквизиты чужой открытой формы?
Да, если у вас есть ссылка на объект формы (например, полученная при открытии через Оповестить или параметры). У формы-владельца вызываются те же методы ПолучитьРеквизиты и индексированное чтение, но делать это стоит только в рамках предусмотренного API формы, иначе логика станет хрупкой при её изменении.
Что важно запомнить
Обход реквизитов формы в 1С строится на методе ПолучитьРеквизиты(): он даёт массив описаний, а значения читаются и пишутся через ЭтаФорма[Имя]. Колонки таблиц обходятся отдельным вызовом с путём, а для полного состава реквизитов объекта используют РеквизитФормыВЗначение и метаданные. Проверяйте существование имён и тестируйте динамические изменения на копии базы.