Как получить доступ к открытой управляемой форме и передать ее данные на сервер?

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

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

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

Анализ фундаментального ограничения платформы

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

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

Проблема поиска формы по заголовку

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


// Не рекомендуется использовать данный подход
ОкнаПриложения = ПолучитьОкна();
Для каждого Элемент Из ОкнаПриложения Цикл
    Если Элемент.Заголовок = "Внутренний документ (создание) *" Тогда
        ФормаОбъекта = Элемент.ПолучитьСодержимое();
        // Пытаемся передать ФормаОбъекта на сервер... ОШИБКА!
    КонецЕсли;
КонецЦикла;

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

Решение №1: Использование экспортных процедур и обратного вызова

Рассмотрим наиболее правильный с точки зрения архитектуры подход. Если нам нужно обработать данные «Формы 2» на сервере, это должна делать сама «Форма 2». Рассмотрим алгоритм по шагам:

  1. В «Форме 2» (целевой форме) создаем экспортную клиентскую процедуру.
  2. В этой процедуре вызываем серверный метод этой же формы.
  3. Внутри серверного метода формы мы имеем полный доступ к данным через ЭтотОбъект (если это модуль формы) или через преобразование РеквизитФормыВЗначение("Объект").

Посмотрим на пример реализации в «Форме 2»:


// В модуле Форма 2
&НаКлиенте
Процедура ВыполнитьОбработкуИзвне() Экспорт
    ВыполнитьОбработкуНаСервере();
КонецПроцедуры

&НаСервере
Процедура ВыполнитьОбработкуНаСервере()
    // Здесь мы имеем доступ к контексту формы
    // Можем вызывать функции интеграции с Документооборотом
    ИнтеграцияС1СДокументооборот.ЗаполнитьСвойствоXDTO(..., ЭтотОбъект, ...);
КонецПроцедуры

Теперь из «Формы 1» нам достаточно просто вызвать эту экспортную процедуру, предварительно сохранив ссылку на форму при её открытии:


// В модуле Форма 1 сохраняем ссылку при открытии
Перем СохраненнаяФорма2;

&НаКлиенте
Процедура ОткрытьВторуюФорму()
    СохраненнаяФорма2 = ОткрытьФорму("Документ.ВнутреннийДокумент.ФормаОбъекта");
КонецПроцедуры

&НаКлиенте
Процедура КомандаОбработать()
    Если СохраненнаяФорма2 <> Неопределено И СохраненнаяФорма2.Открыта() Тогда
        СохраненнаяФорма2.ВыполнитьОбработкуИзвне();
    КонецЕсли;
КонецПроцедуры

Решение №2: Механизм оповещений (ОбработкаОповещения)

Если формы создаются независимо и «Форма 1» не может явно хранить ссылку на «Форму 2», проанализируем механизм глобальных оповещений. Это надежный способ взаимодействия между окнами без жесткой связи. Для решения аналогичной задачи обновления открытой формы после изменения её данных из внешнего контекста можно использовать готовую обработку с примером программного обновления формы документа.

Разберем реализацию этого метода:

  1. «Форма 1» отправляет оповещение через Оповестить("ВыполнитьПрикреплениеФайла", ПараметрыДанных);.
  2. В «Форме 2» создаем обработчик события ОбработкаОповещения.
  3. При получении нужного имени события «Форма 2» сама запускает свои серверные методы.

Пример кода для «Формы 2»:


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

Решение №3: Передача данных через структуру (Лайфхак для интеграций)

Часто в модулях интеграции (например, с 1С:Документооборот) методы требуют параметр Источник или ЭтотОбъект. Проанализируем ситуацию: если мы не можем передать саму форму, можем ли мы передать её данные?

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


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

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

Особенности работы с 1С:Управление нашей фирмой и Документооборотом

В контексте задачи с УНФ и ЭДО, когда необходимо прикрепить файл к документу, который еще только создается, помните о правиле: объект должен существовать в базе данных. Чтобы прикрепить файл (объект ПрисоединенныеФайлы), системе нужна ссылка на владельца. Если «Форма 2» еще не записана, у неё нет ссылки в оперативной памяти (вместо неё — пустая ссылка или Неопределено).

Поэтому правильный алгоритм действий в данном случае будет таким:

  1. В «Форме 1» инициируем процесс.
  2. «Форма 2» при открытии или по оповещению выполняет команду ЭтотОбъект.Записать().
  3. Только после успешной записи на сервере получаем реальную ссылку.
  4. Вызываем методы интеграции, передавая уже записанный объект или его ссылку.

Использование УникальныйИдентификатор формы может помочь вам «связать» две формы через временное хранилище, но помните, что это лишь способ передачи данных, а не контекста выполнения.

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

← На главную