Почему при заполнении табличной части на управляемой форме данные не видны в модуле объекта и как их передать?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке внешних отчетов и обработок на управляемых формах разработчики часто сталкиваются с ситуацией: на стороне формы программно заполняются строки табличной части или дерева, но при вызове процедур модуля объекта прикладной объект оказывается пустым. Разберем причины такого поведения платформы 1С:Предприятие и рассмотрим правильные варианты синхронизации данных между контекстом формы и прикладным объектом.

Архитектурные причины: почему объект «не видит» данные формы

Проанализируем ключевое отличие управляемых форм от обычных:

  1. Отсутствие постоянного экземпляра в памяти: В управляемом приложении серверный экземпляр объекта (например, ВнешнийОтчетОбъект) не хранится в оперативной памяти между вызовами. Он создается динамически при обращении и уничтожается сразу после завершения серверного контекста.
  2. Изоляция модели данных формы: Когда мы выполняем добавление строк через Отчет.ТабличнаяЧасть.Добавить(), мы работаем исключительно со структурой ДанныеФормыКоллекция (или ДанныеФормыДерево). Это модель данных формы, оптимизированная для передачи между клиентом и сервером. Прикладной объект ничего не знает об этих изменениях, пока мы явно не преобразуем данные формы в объект.

Способ 1. Синхронизация через РеквизитФормыВЗначение и ЗначениеВРеквизитФормы

Рассмотрим стандартный и наиболее надежный механизм работы с модулем объекта. Метод РеквизитФормыВЗначение создает новый экземпляр прикладного объекта и автоматически переносит в него все актуальные данные из реквизитов формы, включая заполненные табличные части.

Посмотрим на пример правильной организации серверной процедуры:


&НаСервере
Процедура ВыполнитьОбработкуНаСервере()
    // 1. Создаем прикладной объект отчета с данными из формы
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
    
    // 2. Вызываем экспортный метод модуля объекта, где ТЧ уже будет заполнена
    ОтчетОбъект.СформироватьДанные();
    
    // 3. Если модуль объекта изменил данные, возвращаем их обратно на форму
    ЗначениеВРеквизитФормы(ОтчетОбъект, "Отчет");
КонецПроцедуры

Важный момент: если внутри процедур модуля объекта данные табличной части были модифицированы, обязательно используем метод ЗначениеВРеквизитФормы, иначе пользователь не увидит изменений в интерфейсе.

Способ 2. Преобразование конкретной коллекции через ДанныеФормыВЗначение

Если нам не требуется инициализировать весь объект целиком, а нужно лишь передать конкретную таблицу значений в алгоритм расчета, разберем альтернативный вариант. Мы можем преобразовать отдельную коллекцию формы в универсальную коллекцию значений с помощью функции ДанныеФормыВЗначение.

Посмотрим на реализацию:


&НаСервере
Процедура РассчитатьПоказателиНаСервере()
    // Преобразуем коллекцию формы в ТаблицуЗначений
    ТаблицаДляРасчета = ДанныеФормыВЗначение(Отчет.ДеревоПоказателей, Тип("ТаблицаЗначений"));
    
    // Получаем объект и передаем таблицу параметром в экспортную функцию
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
    ОтчетОбъект.ВыполнитьРасчетПоТаблице(ТаблицаДляРасчета);
КонецПроцедуры

При использовании этого метода обратим внимание на типы данных:

  1. Для табличной части вторым параметром передаем Тип("ТаблицаЗначений").
  2. Если реквизит формы имеет тип ДанныеФормыДерево, вторым параметром необходимо указать Тип("ДеревоЗначений"), иначе платформа вызовет исключение несоответствия типов.

Способ 3. Оптимизация заполнения больших массивов данных

Построчное добавление строк в ДанныеФормыКоллекция через цикл с методом Добавить() работает значительно медленнее, чем прямая работа с таблицами в памяти. Если требуется загрузить большой объем данных, разберем более производительную схему:

  1. Сначала получаем объект с помощью РеквизитФормыВЗначение.
  2. Заполняем табличную часть объекта быстрыми методами (например, Загрузить() или прямым заполнением в памяти).
  3. Один раз выгружаем результат в форму через ЗначениеВРеквизитФормы.

Посмотрим на пример оптимизированного кода:


&НаСервере
Процедура ЗаполнитьБольшуюТабличнуюЧастьНаСервере(ВходнаяТаблица)
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
    
    // Быстро загружаем данные напрямую в табличную часть объекта
    ОтчетОбъект.ДеревоПоказателей.Загрузить(ВходнаяТаблица);
    
    // Синхронизируем изменения с формой за один вызов
    ЗначениеВРеквизитФормы(ОтчетОбъект, "Отчет");
КонецПроцедуры

Ограничения на хранение переменных в модуле объекта

Выясним еще одну важную деталь: переменные, объявленные в модуле объекта с ключевым словом Экспорт, не сохраняют свои значения между отдельными вызовами с клиента на сервер. При каждом новом серверном вызове создается чистый экземпляр объекта. Поэтому для долговременного хранения данных между кликами пользователя следует использовать либо реквизиты самой формы, либо механизм ПоместитьВоВременноеХранилище и ПолучитьИзВременногоХранилища.

← На главную