Как сохранить и обработать данные объекта одной формы при возврате из другой формы в 1С?

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

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

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

Причина проблемы: жизненный цикл серверного объекта

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

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

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

Шаг 1. Правильная передача данных через Оповещение

Выясним, как организовать передачу данных из формы выбора (Форма 2) в основную форму (Форма 1). Автор использовал механизм Оповестить. Это рабочий инструмент, но он требует аккуратности. Посмотрим на пример реализации в Форме 2:


&НаКлиенте
Процедура ДобавитьДокументыКЗадаче(Команда)
    // Формируем массив или таблицу выбранных документов
    Если тзЖурналДокументов.Количество() > 0 Тогда
        // Параметр может содержать массив ссылок или таблицу значений
        Оповестить("ДобавлениеДокумента", тзЖурналДокументов);
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

Теперь разберем, что происходит в Форме 1. Процедура ОбработкаОповещения работает на клиенте. Чтобы обработать полученные данные и сопоставить их с текущим объектом, нам нужно «сходить» на сервер.


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

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

Шаг 2. Исключение дубликатов при добавлении строк

Проанализируем ситуацию с проверкой существующих записей. Пользователь в Сообщении 4 задается вопросом: как проверить наличие строк, если таблицы «живут» на разных формах? На самом деле, проверку нужно делать в тот момент, когда данные уже переданы в Форму 1.

Для эффективного поиска дублей в табличной части (или коллекции ДанныеФормыКоллекция) лучше всего использовать метод НайтиСтроки. Рассмотрим по шагам, как это реализовать внутри серверной процедуры:


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

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

Шаг 3. Использование Временного хранилища для больших объемов

Как справедливо замечено в Сообщении 14, при передаче больших наборов данных (например, если в списке выбора тысячи документов) механизм Оповестить может работать медленно, так как данные сериализуются и передаются через клиент. Рассмотрим более профессиональный подход с использованием временного хранилища.

  1. В Форме 2: Помещаем данные во временное хранилище и передаем в Оповестить только адрес.
  2. В Форме 1: Получаем данные по адресу и очищаем хранилище.

Посмотрим на пример реализации этого метода:


// В Модуле Формы 2
&НаСервере
Функция ПоместитьДанныеВХранилище()
    // Создаем структуру или таблицу для передачи
    ДанныеДляПередачи = тзЖурналДокументов.Выгрузить();
    Возврат ПоместитьВоВременноеХранилище(ДанныеДляПередачи, ЭтаФорма.УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура ДобавитьДокументы(Команда)
    АдресДанных = ПоместитьДанныеВХранилище();
    Оповестить("ДобавлениеДокумента", АдресДанных);
    ЭтаФорма.Закрыть();
КонецПроцедуры

В основной форме (Форма 1) обработка будет выглядеть так:


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

Шаг 4. Альтернативный метод: ОбработкаВыбора

Разберем еще один способ, который считается более «чистым» в архитектуре 1С — использование стандартного события ОбработкаВыбора. Вместо того чтобы использовать глобальное оповещение, мы можем связать формы напрямую.

При открытии Формы 2 укажем Форму 1 в качестве владельца:


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

В Форме 2 при выборе документа достаточно вызвать Закрыть(РезультатВыбора). Тогда в Форме 1 автоматически сработает стандартный обработчик:


&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
    // ВыбранноеЗначение придет сюда напрямую
    Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
        ДобавитьДокументыНаСервере(ВыбранноеЗначение);
    КонецЕсли;
КонецПроцедуры

Подведем итоги

Для того чтобы данные не терялись и корректно обрабатывались при взаимодействии форм, придерживайтесь следующих правил:

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

← На главную