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

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

1С: как обратиться к программно созданному реквизиту формы

Как в 1С обратиться к программно созданному реквизиту формы: ИзменитьРеквизиты, обращение через ЭтаФорма[Имя], типичные ошибки и примеры кода.

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

Ключевой момент — порядок действий. Доступ к реквизиту возможен только после того, как метод ИзменитьРеквизиты() отработал. Попытка прочитать или записать значение до этого вызова гарантированно приводит к ошибке исполнения. Также важно различать обращение к самому реквизиту (его значению) и обращение к элементу формы, который этот реквизит отображает.

Как программно создаётся реквизит формы

Динамическое добавление реквизитов выполняется методом формы ИзменитьРеквизиты(). Метод принимает два параметра: массив добавляемых реквизитов и массив удаляемых (второй можно опустить). Каждый новый реквизит описывается объектом ОписаниеРеквизитаФормы, который конструируется оператором Новый РеквизитФормы(Имя, ОписаниеТипов, Путь, Заголовок, СохраняемыеДанные).

Типичный код добавления выглядит так:

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

ДобавляемыеРеквизиты = Новый Массив;

ОписаниеТипов = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100));

НовыйРеквизит = Новый РеквизитФормы("КомментарийДинамический", ОписаниеТипов, "", "Комментарий", Ложь);

ДобавляемыеРеквизиты.Добавить(НовыйРеквизит);

ИзменитьРеквизиты(ДобавляемыеРеквизиты);

КонецПроцедуры

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

Обращение к реквизиту по имени через ЭтаФорма

После выполнения ИзменитьРеквизиты() новый реквизит становится свойством управляемой формы. Обратиться к нему можно двумя равнозначными способами. Первый — прямое обращение по имени в контексте модуля формы:

ЭтаФорма["КомментарийДинамический"] = "Текст комментария";

Значение = ЭтаФорма["КомментарийДинамический"];

Квадратные скобки со строковым литералом — самый надёжный вариант, потому что имя можно сформировать динамически, например собрать из префикса и идентификатора строки таблицы. Это особенно удобно, когда реквизиты создаются в цикле по набору данных: ЭтаФорма["Поле_" + ИдентификаторСтроки].

Второй способ — обращение через точку: КомментарийДинамический = "Текст" внутри модуля формы. Он работает, но имеет недостаток: редактор кода не проверяет такое имя, а при опечатке ошибка проявится только в момент выполнения. Для динамических реквизитов предпочтительнее синтаксис с квадратными скобками — он явно показывает, что имя вычисляется.

Обращение с клиента и с сервера

Значение реквизита формы доступно и в клиентских, и в серверных процедурах модуля формы — данные формы автоматически передаются между контекстами. Чтение и запись ЭтаФорма["Имя"] работают и в директиве &НаКлиенте, и в &НаСервере.

Различие в другом: изменить состав реквизитов (добавить или удалить) можно только на сервере. Если по действию пользователя нужно создать новый реквизит, придётся организовать серверный вызов из клиентского обработчика:

&НаКлиенте

Процедура ДобавитьПоле(Команда)

ДобавитьПолеНаСервере();

ЭтаФорма["НовоеПоле"] = "Начальное значение"; // уже на клиенте

КонецПроцедуры

&НаСервере

Процедура ДобавитьПолеНаСервере()

МассивРеквизитов = Новый Массив;

МассивРеквизитов.Добавить(Новый РеквизитФормы("НовоеПоле",

Новый ОписаниеТипов("Строка"), "", "Новое поле", Ложь));

ИзменитьРеквизиты(МассивРеквизитов);

КонецПроцедуры

Частые серверные вызовы при интерактивной работе замедляют форму, особенно на медленных каналах. Если заранее известен максимальный набор реквизитов, разумнее создать их все один раз в ПриСозданииНаСервере и управлять только видимостью связанных элементов.

Обращение к элементу формы, связанному с реквизитом

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

НовыйЭлемент = Элементы.Добавить("ПолеКомментария", Тип("ПолеФормы"), ЭтаФорма);

НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;

НовыйЭлемент.ПутьКДанным = "КомментарийДинамический";

НовыйЭлемент.Заголовок = "Комментарий";

Здесь важно не путать три разных имени: имя реквизита (КомментарийДинамический), имя элемента формы (ПолеКомментария) и путь к данным. К значению обращаются по имени реквизита, к свойствам отображения (видимость, доступность, заголовок) — через Элементы.ПолеКомментария или Элементы["ПолеКомментария"].

Если элементов много и они создаются в цикле, используйте предсказуемую схему именования, например "Поле_" + ИмяРеквизита. Тогда в любом месте кода элемент находится однозначно: Элементы["Поле_" + ИмяРеквизита].Видимость = Ложь.

Типичные ошибки
01
Обращение к реквизиту до вызова ИзменитьРеквизиты — ошибка «Поле объекта не обнаружено», потому что реквизит ещё не существует.
02
Попытка вызвать ИзменитьРеквизиты в клиентской процедуре — метод доступен только на сервере.
03
Путаница между именем реквизита и именем элемента формы: Элементы.ИмяРеквизита не найдёт элемент, если он назван иначе.
04
Повторное добавление реквизита с тем же именем при повторном серверном вызове — исключение о дублировании. Перед добавлением проверяйте существование.

Проверка существования реквизита перед обращением

Если логика формы допускает, что реквизит может быть не создан (например, добавление происходит условно), перед обращением стоит убедиться в его наличии. Прямого метода «НайтиРеквизит» у формы нет, поэтому используют обход структуры реквизитов через ПолучитьРеквизиты():

Функция РеквизитСуществует(ИмяРеквизита)

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

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

Возврат Истина;

КонецЕсли;

КонецЦикла;

Возврат Ложь;

КонецФункции

Альтернатива — обращение через ЭтаФорма[Имя] внутри Попытка...Исключение, но это худший вариант: исключения медленнее и маскируют реальные ошибки. Для табличных частей формы метод ПолучитьРеквизиты(Путь) принимает путь к таблице, что позволяет проверять и колонки динамически созданных таблиц.

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

Динамические таблицы значений и обращение к колонкам

Частый сценарий — программно созданная таблица значений как реквизит формы с набором колонок. Обращение к такой таблице идёт по имени реквизита, а к ячейкам — через строки коллекции:

// Создание

Реквизиты = Новый Массив;

Реквизиты.Добавить(Новый РеквизитФормы("ТаблицаДанных",

Новый ОписаниеТипов("ТаблицаЗначений"), "", "Данные", Ложь));

Реквизиты.Добавить(Новый РеквизитФормы("Номенклатура",

Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "ТаблицаДанных", "Номенклатура", Ложь));

ИзменитьРеквизиты(Реквизиты);

// Обращение

Строка = ЭтаФорма["ТаблицаДанных"].Добавить();

Строка.Номенклатура = ТекущаяНоменклатура;

Обратите внимание на путь при создании колонки: третий параметр конструктора РеквизитФормы указывает путь к родительской таблице. Без этого колонка создастся как самостоятельный реквизит верхнего уровня, и обращение Строка.Номенклатура вызовет ошибку.

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

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

Открытие формы
Норма

Форма открывается без исключений, поля видны

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

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

Запись и чтение значения
Норма

ЭтаФорма["Имя"] возвращает записанное значение

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

Возвращается Неопределено или пустое значение при заполненном поле — перепутаны реквизит и элемент

Повторный серверный вызов
Норма

Форма работает стабильно

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

Ошибка дублирования реквизита — добавление выполняется повторно без проверки

Ограничения и риски динамических реквизитов

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

Второй риск — производительность. Каждый вызов ИзменитьРеквизиты() перестраивает данные формы, что при большом количестве реквизитов и частых вызовах ощутимо замедляет работу. Создавайте весь набор за один вызов, передавая полный массив.

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

Итог

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

Программно созданный реквизит доступен через ЭтаФорма["Имя"] сразу после ИзменитьРеквизиты. Создание — только на сервере, обращение — и на клиенте, и на сервере. Различайте реквизит (данные) и элемент формы (отображение), проверяйте существование перед обращением и не добавляйте реквизит дважды.

Частые вопросы

Можно ли обратиться к программному реквизиту из другой формы?

Напрямую — нет, реквизит существует только внутри своей формы. Передайте владельцу формы ссылку на неё и добавьте экспортную функцию, возвращающую значение, либо используйте ОповеститьОВыборе / структуру возврата при закрытии.

Почему ЭтаФорма["Имя"] выдаёт «Поле объекта не обнаружено»?

Чаще всего обращение выполняется до ИзменитьРеквизиты или имя не совпадает с заданным при создании. Проверьте порядок вызовов и точное написание имени, включая путь для колонок таблиц.

Как удалить программно созданный реквизит?

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

Можно ли создать реквизит в обработчике на клиенте?

Нет, ИзменитьРеквизиты работает только в серверном контексте. Из клиентского обработчика вызовите серверную процедуру, выполните добавление там, а затем продолжите работу на клиенте.

Сохраняются ли значения динамических реквизитов при закрытии формы?

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

Чем отличается ПутьКДанным элемента от имени реквизита?

ПутьКДанным указывает, откуда элемент берёт значение, и обычно совпадает с именем реквизита. Имя элемента — отдельный идентификатор для обращения через Элементы; оно может быть любым уникальным.