Как передать узел дерева значений с клиента на сервер для обработки и отображения прогресса в 1С?

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

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

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

В управляемом приложении 1С существует четкое разделение между типами данных, доступными на клиенте, и типами на сервере. Объект ДанныеФормыЭлементДерева — это специализированная программная оболочка (прокси-объект), которая предназначена исключительно для связи интерфейса с данными формы. Этот тип не является сериализуемым в том смысле, в котором сервер ожидает получить параметры. Сервер "не знает", как работать с конкретным интерфейсным узлом вне контекста всей формы.

Для решения этой проблемы мы проанализируем три основных подхода: использование идентификаторов, преобразование всей коллекции и работу через временные структуры.

Способ 1: Передача идентификатора строки (Рекомендуемый для циклов)

Самый простой и эффективный способ передать "ссылку" на конкретную строку дерева — это использование её уникального идентификатора. Каждая строка в коллекции данных формы имеет внутренний числовой ID, который остается неизменным в рамках текущего сеанса работы формы. Разберем этот метод по шагам.

Шаг 1. Обход дерева на клиенте. Мы используем рекурсию или простой цикл для получения идентификатора каждой строки.


&НаКлиенте
Процедура ОбработатьДеревоНаКлиенте()
    
    // Получаем корневые элементы дерева
    КорневыеЭлементы = ДеревоОбъект.ПолучитьЭлементы();
    
    Для Каждого ТекущийУзел Из КорневыеЭлементы Цикл
        ОбработатьРекурсивно(ТекущийУзел);
    КонецЦикла;
    
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьРекурсивно(УзелДерева)
    
    // Получаем идентификатор строки
    ИдентификаторСтроки = УзелДерева.ПолучитьИдентификатор();
    
    // Вызываем серверный метод, передавая только число (ID)
    ОбработатьСтрокуНаСервере(ИдентификаторСтроки);
    
    // Индикация прогресса для пользователя
    Состояние("Обработка строки: " + УзелДерева.Наименование);
    
    // Рекурсивный обход подчиненных элементов
    ПодчиненныеЭлементы = УзелДерева.ПолучитьЭлементы();
    Для Каждого ДочернийУзел Из ПодчиненныеЭлементы Цикл
        ОбработатьРекурсивно(ДочернийУзел);
    КонецЦикла;
    
КонецПроцедуры

Шаг 2. Поиск строки на сервере. Теперь на стороне сервера нам нужно восстановить доступ к данным строки, используя полученный идентификатор и метод НайтиПоИдентификатору().


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

Способ 2: Преобразование дерева в универсальный объект

Если логика обработки требует анализа всего дерева сразу (например, расчет итогов по иерархии или массовое изменение связей), лучше передать данные целиком один раз, преобразовав их в тип ДеревоЗначений. Это избавит нас от множества "коротких" вызовов сервера, которые сильно замедляют работу в веб-клиенте или при плохом интернет-соединении.

Проанализируем пример использования функции ДанныеФормыВЗначение:


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

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

Организация плавной индикации прогресса

Выясним причину, по которой пользователь часто видит "рывки" при обновлении индикатора. Если вызывать ОбновитьНаСервере() внутри цикла на клиенте, интерфейс будет "подмораживаться" на время каждого сетевого запроса. Для достижения максимально гладкого визуального эффекта рекомендуется:

  1. Использовать команду ОбработкаПрерыванияПользователя() внутри цикла, чтобы дать системе возможность перерисовать форму.
  2. Применять метод Состояние() для отображения системного прогресс-бара в нижней части экрана.
  3. Если операция очень длительная (более 10-20 секунд), использовать механизмы длительных операций (фоновые задания).

Рассмотрим вариант с использованием структуры, если нам нужно передать на сервер данные, которых еще нет в базе данных или которые были изменены пользователем, но не записаны:


&НаКлиенте
Процедура ПередатьДанныеЧерезСтруктуру(УзелДерева)
    
    ПараметрыУзла = Новый Структура;
    ПараметрыУзла.Вставить("Код", УзелДерева.Код);
    ПараметрыУзла.Вставить("Количество", УзелДерева.Количество);
    
    // Структура прекрасно передается на сервер без ошибок
    ВыполнитьРасчетНаСервере(ПараметрыУзла);
    
КонецПроцедуры

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

Проанализируем ситуацию: если в дереве 1000 строк, и для каждой мы вызываем сервер, мы получаем 1000 сетевых пакетов "туда-обратно". В условиях работы через интернет каждый такой вызов может занимать от 50 до 200 мс. В сумме это даст огромную задержку только на передачу данных.

Совет: Вместо обработки одной строки за один вызов, передавайте массив идентификаторов (пачки по 50-100 штук). Это позволит сохранить визуальную индикацию (обновляя прогресс после каждой пачки) и значительно увеличит скорость работы за счет сокращения количества серверных вызовов.

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

← На главную