Как передать данные табличной части между формами внешней обработки в 1С 8.3?

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

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

В этой статье мы подробно проанализируем, почему так происходит, разберем внутренние механизмы платформы и рассмотрим несколько эффективных способов передачи данных (включая табличные части) из одной формы в другую.

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

Для начала разберем ситуацию, описанную автором: в первой форме основной реквизит Объект содержит заполненную табличную часть МояТЧ. При открытии второй формы через метод ОткрытьФорму() программист ожидает, что основной реквизит Объект второй формы будет содержать те же данные. Однако попытка преобразовать данные формы в объект на сервере через РеквизитФормыВЗначение("Объект") показывает, что табличная часть пуста.

Рассмотрим причину этого поведения:

  1. Разные экземпляры объектов. В управляемом приложении, когда вы вызываете метод ОткрытьФорму() для внешней обработки, система создает новый программный экземпляр этой обработки в оперативной памяти сервера. Вторая форма никак не связана с данными первой формы автоматически, даже если они принадлежат одному файлу обработки.
  2. Данные формы — это не сам объект. Реквизит Объект в управляемой форме имеет тип ДанныеФормыСтруктура. Это лишь проекция данных, предназначенная для отображения в интерфейсе. Метод РеквизитФормыВЗначение создает временный объект в памяти сервера только на время выполнения серверной процедуры, и он инициализируется значениями из текущей формы.
  3. Отличие от обычных форм. В старых версиях (7.7 или 8.2 толстый клиент) объект жил в памяти, пока была открыта хотя бы одна форма. В управляемом приложении данные живут внутри контекста конкретной формы. Как только контекст формы заканчивается (или создается новая форма), старые данные не перетекают в новые автоматически.

Таким образом, наша задача — явно передать данные из контекста одной формы в контекст другой. Рассмотрим, как это сделать правильно.

Способ 1: Использование метода КопироватьДанныеФормы

Этот способ наиболее прост и нагляден, когда нам нужно открыть вторую форму и сразу «вбросить» в неё все данные из первой. Мы сначала программно получаем форму, заполняем её реквизиты и только потом открываем её пользователю.

Рассмотрим пример реализации:


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

В данном случае метод КопироватьДанныеФормы выполняет глубокое копирование всех реквизитов, включая табличные части. Во второй форме в процедуре ПриСозданииНаСервере табличная часть уже будет заполнена к моменту начала работы кода.

Способ 2: Передача данных через Временное хранилище (Рекомендуется)

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

Проанализируем этот алгоритм:

  1. В первой форме выгружаем табличную часть в таблицу значений (ТЗ).
  2. Помещаем ТЗ во временное хранилище и получаем уникальный адрес.
  3. Передаем этот адрес как параметр при открытии второй формы.
  4. Во второй форме на сервере извлекаем данные и загружаем их в ТЧ.

Пример кода для первой формы:


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

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

Пример кода для второй формы (в модуле формы):


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

Нюансы работы с методом РеквизитФормыВЗначение

Разберем ошибку автора, связанную с РеквизитФормыВЗначение("Объект"). Программист ожидал увидеть там заполненный объект. Важно помнить: этот метод всегда создает объект на основе данных ТЕКУЩЕЙ формы. Если в Объект.МояТЧ во второй форме на момент вызова пусто, то и в полученном значении ОбработкаОбъект будет пусто.

Этот метод используется не для передачи данных между формами, а для вызова методов объекта (процедур и функций из модуля обработки), которые недоступны напрямую из модуля формы. Например, если у вас в модуле обработки есть сложная функция расчета, вы делаете так:


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

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

Заключение

Подведем итоги нашего анализа. Для того чтобы успешно работать с данными одной внешней обработки в разных формах, необходимо отказаться от парадигмы «единого объекта» и использовать механизмы явной передачи данных.

Выделим ключевые правила:

Соблюдение этих принципов позволит вам создавать стабильные и быстрые интерфейсы в управляемом приложении 1С.

← На главную