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