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