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