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