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