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