Как передать ветвь дерева значений в другую форму без ошибки отображения типов?

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

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

Почему возникает «Ошибка отображения типов»?

Прежде всего, проанализируем архитектуру управляемого приложения. Данные, с которыми мы работаем на форме (дерево значений, таблицы), имеют специальные типы: ДанныеФормыДерево, ДанныеФормыКоллекция и ДанныеФормыЭлементДерева. Эти типы предназначены исключительно для отображения данных в интерфейсе и взаимодействия с элементами управления. Они не являются сериализуемыми, то есть платформа не может «упаковать» их и передать через границу между двумя формами или между клиентом и сервером в произвольном контексте.

Параметры, которые мы передаем в функцию ОткрытьФорму(), должны содержать только простые типы (числа, строки, даты, булево), ссылки на объекты базы данных или коллекции (массивы, структуры), состоящие из этих же простых типов. Попытка вставить в структуру параметров «живой» объект данных формы и вызывает ту самую ошибку.

Способ №1: Использование временного хранилища (Рекомендуемый)

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

Разберем по шагам алгоритм реализации:

  1. На стороне первой формы (отправитель): Мы должны преобразовать нужную ветку дерева в обычную ТаблицуЗначений или ДеревоЗначений на сервере, поместить этот объект во временное хранилище и передать адрес хранилища в параметрах открытия второй формы.
  2. На стороне второй формы (получатель): В обработчике ПриСозданииНаСервере мы извлекаем объект по адресу, преобразуем его обратно в данные формы и отображаем пользователю.

Пример кода для первой формы (выгрузка ветви в таблицу значений и помещение в хранилище):


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

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

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

Способ №2: Передача через массив структур (Для небольших объемов)

Если данных в ветви немного (например, до 50–100 строк), мы можем обойтись без временного хранилища. Рассмотрим ситуацию, когда мы формируем массив, где каждый элемент — это структура, представляющая строку данных.

Выясним преимущества этого метода: массив структур является сериализуемым, а значит, его можно передать напрямую в параметре ОткрытьФорму. Это упрощает код, так как нам не нужно управлять временем жизни данных в хранилище.


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

Способ №3: Использование владельца формы и клиентских методов

Посмотрим на более «хитрый» способ, упомянутый в обсуждении. Мы можем передать в качестве владельца открываемой формы нашу текущую форму. Тогда во второй форме через свойство ВладелецФормы можно получить доступ к контексту первой формы.

Однако, стоит помнить, что прямое обращение к коллекции данных владельца через ВладелецФормы.Объект.Дерево... может быть ограничено или приводить к нестабильной работе, если не соблюдена типизация. Правильнее будет вызвать экспортный метод в основной форме. Это позволяет передать данные «по ссылке» в рамках клиентского сеанса без сериализации через сервер.

Синхронизация данных: Как вернуть результат обратно?

Просто передать данные недостаточно — нужно вернуть отредактированные значения назад в исходное дерево. Для этого лучше всего использовать механизм Описания Оповещения.

Рассмотрим по шагам процесс возврата:

  1. При открытии формы создаем объект ОписаниеОповещения, указывая процедуру, которая выполнится после закрытия второй формы.
  2. Во второй форме, после завершения редактирования, вызываем Закрыть(Результат), где Результат — это структура с измененными данными.
  3. В процедуре обратного вызова первой формы находим исходную строку дерева (например, по уникальному ключу или индексу) и обновляем её значения.

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

Резюме

Для эффективной обработки ветвей дерева значений в разных формах мы рекомендуем:

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

← На главную