К статье
Практический материал

Разработка и Конфигурация · 10 мин

1С: как обойти реквизиты формы программно

Как программно обойти реквизиты формы в 1С: ПолучитьРеквизиты, РеквизитФормыВЗначение, обход колонок таблицы значений. Примеры кода, ошибки и проверка результата.

Обход реквизитов формы — типовая задача при разработке на управляемых формах 1С: нужно перебрать все реквизиты, найти нужные по имени или типу, скопировать значения, очистить форму или проверить заполненность. Напрямую «пройтись циклом» по реквизитам формы нельзя — у объекта «УправляемаяФорма» нет коллекции реквизитов в привычном смысле. Но платформа даёт несколько рабочих механизмов, и выбор зависит от того, что именно требуется: имена, значения, типы или структура табличных частей формы.

Основной инструмент — метод формы ПолучитьРеквизиты(), который возвращает массив объектов «РеквизитФормы». У каждого элемента массива есть свойства «Имя», «Путь», «ТипЗначения» и «Заголовок», по которым и строится обход. Для работы со значениями применяют обращение через «ЭтаФорма[ИмяРеквизита]» либо преобразование «РеквизитФормыВЗначение».

Как устроены реквизиты формы и почему простой цикл не работает

На управляемой форме реквизиты — это не свойства объекта формы, а отдельная коллекция данных, описанная в дереве реквизитов формы. Обращение «ЭтаФорма.МойРеквизит» работает благодаря механизму расширения формы, но перечислить такие свойства через «Для Каждого» напрямую нельзя: коллекция не экспонируется как итерируемый объект.

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

Базовый обход через ПолучитьРеквизиты

Минимальный рабочий код обхода всех реквизитов верхнего уровня выглядит так:

РеквизитыФормы = ЭтаФорма.ПолучитьРеквизиты();

Для Каждого Реквизит Из РеквизитыФормы Цикл

ИмяРеквизита = Реквизит.Имя;

ТипРеквизита = Реквизит.ТипЗначения;

Значение = ЭтаФорма[ИмяРеквизита];

Сообщить(ИмяРеквизита + " : " + Строка(Значение));

КонецЦикла;

Здесь важно различать объект описания реквизита и само значение. «Реквизит.Имя» — строка, «Реквизит.ТипЗначения» — описание типов, а значение извлекается индексированным обращением «ЭтаФорма[Имя]». Такой приём работает и для записи: «ЭтаФорма[Имя] = НовоеЗначение» — удобно, когда имя реквизита заранее неизвестно и вычисляется динамически.

Учтите, что ПолучитьРеквизиты() без параметров вернёт только реквизиты верхнего уровня: колонки таблиц и реквизиты вложенных структур в массив не попадут. Их обход выполняется отдельным вызовом с указанием пути.

Порядок действий для обхода реквизитов
  1. 1
    Вызовите ЭтаФорма.ПолучитьРеквизиты() и сохраните массив
  2. 2
    Переберите массив циклом Для Каждого
  3. 3
    Отфильтруйте реквизиты по имени, типу или пути, если нужны не все
  4. 4
    Прочитайте значение через ЭтаФорма[Реквизит.Имя]
  5. 5
    Проверьте результат в отладчике или через Сообщить

Обход колонок таблицы значений на форме

Таблицы значений и динамические списки на форме — частый источник вопросов. Чтобы обойти колонки таблицы «Товары», передайте её имя в ПолучитьРеквизиты:

Колонки = ЭтаФорма.ПолучитьРеквизиты("Товары");

Для Каждого Колонка Из Колонки Цикл

Сообщить("Колонка: " + Колонка.Имя + ", тип: " + Колонка.ТипЗначения);

КонецЦикла;

Для обхода строк таблицы с доступом к значениям ячеек используется стандартный цикл по коллекции данных формы:

Для Каждого СтрокаТаблицы Из ЭтаФорма.Товары Цикл

Для Каждого Колонка Из Колонки Цикл

ЗначениеЯчейки = СтрокаТаблицы[Колонка.Имя];

КонецЦикла;

КонецЦикла;

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

Альтернатива: обход через РеквизитФормыВЗначение

Если на форме один основной реквизит объекта (например, «Объект» в форме документа или справочника), часто удобнее не обходить реквизиты формы, а преобразовать данные в прикладной объект: ЭтаФорма.РеквизитФормыВЗначение("Объект"). У полученного объекта уже есть метаданные, и обход реквизитов выполняется через «Метаданные().Реквизиты»:

ОбъектДанные = ЭтаФорма.РеквизитФормыВЗначение("Объект");

Для Каждого РеквизитМД Из ОбъектДанные.Метаданные().Реквизиты Цикл

Значение = ОбъектДанные[РеквизитМД.Имя];

КонецЦикла;

Этот способ даёт доступ ко всем реквизитам объекта конфигурации, включая те, что не выведены на форму. Обратная сторона — преобразование «РеквизитФормыВЗначение» создаёт копию данных и может быть ресурсоёмким на больших объектах, а изменения вернутся на форму только после «ЗначениеВРеквизитФормы».

Сравнение подходов

ПолучитьРеквизиты

Подходит для обхода именно реквизитов формы, включая добавленные программно. Не показывает реквизиты объекта, скрытые от формы.

РеквизитФормыВЗначение + Метаданные

Подходит для обхода реквизитов прикладного объекта целиком. Требует основного реквизита формы и затрат на преобразование.

ЭтаФорма[Имя] по списку имён

Подходит, когда набор реквизитов известен заранее или формируется по шаблону имён. Самый быстрый вариант.

Практические сценарии: очистка, копирование, проверка заполненности

Очистка всех реквизитов формы

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

Для Каждого Реквизит Из ЭтаФорма.ПолучитьРеквизиты() Цикл

Если Реквизит.Имя = "Объект" Тогда

Продолжить; // основной объект не трогаем

КонецЕсли;

ЭтаФорма[Реквизит.Имя] = Неопределено;

КонецЦикла;

Проверка заполненности без жёсткого списка

Для произвольной формы можно проверить, какие реквизиты не заполнены, используя «ЗначениеЗаполнено»:

Для Каждого Реквизит Из ЭтаФорма.ПолучитьРеквизиты() Цикл

Если Не ЗначениеЗаполнено(ЭтаФорма[Реквизит.Имя]) Тогда

Сообщить("Не заполнен реквизит: " + Реквизит.Заголовок);

КонецЕсли;

КонецЦикла;

Копирование значений между формами

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

Типичные ошибки и ограничения

Самая частая ошибка — попытка прочитать «Реквизит.Значение». У объекта «РеквизитФормы» нет такого свойства: значение хранится в данных формы и доступно только через «ЭтаФорма[Имя]». Вторая распространённая проблема — ожидание, что ПолучитьРеквизиты() вернёт колонки таблиц: без параметра пути они не возвращаются.

Также учитывайте контекст выполнения. В клиент-серверном режиме обращение «ЭтаФорма[Имя]» на клиенте работает только для реквизитов, чьи типы доступны на клиенте. Для сложных серверных типов обход выполняйте в серверной процедуре с директивой «&НаСервере».

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

Типичные ошибки
01
Обращение к Реквизит.Значение — свойства не существует, значение читается через ЭтаФорма[Имя]
02
Обход без фильтра служебных реквизитов — очищается или затирается основной объект формы
03
Вызов ПолучитьРеквизиты() в ожидании колонок таблиц — нужно передавать путь к таблице параметром
04
Обращение к ЭтаФорма[Имя] с несуществующим именем — исключение времени выполнения, имя надо проверять заранее

Как проверить результат обхода

После реализации обхода убедитесь, что массив реквизитов не пуст и содержит ожидаемые элементы. Проще всего вывести имена в отладчике: поставьте точку останова внутри цикла и посмотрите содержимое «Реквизит.Имя» и «Реквизит.ТипЗначения». Если массив пуст — проверьте, что код выполняется в контексте формы, а не в модуле объекта или общем модуле без передачи формы.

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

Контрольные точки

Как проверить результат

Массив ПолучитьРеквизиты()
Норма

Содержит элементы с заполненными Имя и ТипЗначения

Тревожный признак

Пустой массив — код выполнен не в контексте формы

Чтение ЭтаФорма[Имя]
Норма

Возвращается значение без исключения

Тревожный признак

Ошибка «Поле объекта не обнаружено» — имени нет среди реквизитов

Запись значений в цикле
Норма

Поля формы обновились на экране

Тревожный признак

Изменения не видны — запись шла в копию после РеквизитФормыВЗначение без обратного преобразования

FAQ: частые вопросы об обходе реквизитов формы

Можно ли обойти реквизиты формы на обычных формах?

На обычных формах механизм другой: там доступны метаданные объекта и реквизиты через структуру формы, но метода ПолучитьРеквизиты нет. Обычно обходят реквизиты объекта через Метаданные() либо перебирают элементы управления формы. Описанные в статье приёмы относятся к управляемым формам.

Как найти реквизит формы по части имени?

Переберите массив ПолучитьРеквизиты() и используйте строковые функции: СтрНайти(Реквизит.Имя, "Префикс") или Лев()/Прав() для сравнения. Так можно собрать, например, все реквизиты с префиксом «Настройка_» и обработать их группой.

Почему в цикле не видны колонки таблицы значений?

ПолучитьРеквизиты() без параметров возвращает только реквизиты верхнего уровня. Колонки конкретной таблицы получают вызовом ПолучитьРеквизиты("ИмяТаблицы"), а затем обходят отдельным циклом.

Как обойти программно добавленные реквизиты формы?

Реквизиты, добавленные методом ИзменитьРеквизиты, попадают в тот же массив ПолучитьРеквизиты() и обходятся одинаково. Главное — выполнять обход после того, как состав реквизитов изменён, иначе новые элементы в массив не попадут.

Чем опасен обход через РеквизитФормыВЗначение в цикле?

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

Можно ли обойти реквизиты чужой открытой формы?

Да, если у вас есть ссылка на объект формы (например, полученная при открытии через Оповестить или параметры). У формы-владельца вызываются те же методы ПолучитьРеквизиты и индексированное чтение, но делать это стоит только в рамках предусмотренного API формы, иначе логика станет хрупкой при её изменении.

Итог

Что важно запомнить

Обход реквизитов формы в 1С строится на методе ПолучитьРеквизиты(): он даёт массив описаний, а значения читаются и пишутся через ЭтаФорма[Имя]. Колонки таблиц обходятся отдельным вызовом с путём, а для полного состава реквизитов объекта используют РеквизитФормыВЗначение и метаданные. Проверяйте существование имён и тестируйте динамические изменения на копии базы.