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