Как программно заполнить форму документа из внешней обработки и обновить данные на экране

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

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

Разбор проблемы: почему данные не обновляются автоматически

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

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

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

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

Шаг 1. Подготовка данных на сервере. В серверной процедуре внешней обработки мы получаем файл, создаем объект документа и заполняем его. Затем мы преобразуем этот объект в данные формы, которые были переданы через параметры.


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

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


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

Решение №2: Использование механизмов БСП для заполнения объектов

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

В серверном методе ВыполнитьКоманду внешней обработки БСП передает параметр Объект, который является прямой проекцией данных формы. Рассмотрим, как это выглядит в модуле обработки:


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

В этом случае БСП сама контролирует контекст, и после завершения серверного метода данные на форме обновятся автоматически. Это более «чистый» способ с точки зрения архитектуры системы.

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

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

  1. В основной форме документа мы переопределяем обработчик ОбработкаОповещения.
  2. Во внешней обработке после завершения всех серверных действий вызываем метод Оповестить("СобытиеЗаполнениеЗавершено", ДанныеДляЗаполнения, ЭтаФорма).
  3. Форма документа «ловит» это событие и выполняет обновление данных в своем собственном серверном контексте.

Рассмотрим пример кода для формы документа:


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

&НаСервере
Процедура ОбновитьДанныеФормыНаСервере(АдресХранилища)
    НовыйОбъект = ПолучитьИзВременногоХранилища(АдресХранилища);
    ЗначениеВДанныеФормы(НовыйОбъект, Объект);
КонецПроцедуры

Важные нюансы при заполнении форм

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

1. Флаг модифицированности. Программное изменение Объект.ИмяРеквизита на клиенте или использование КопироватьДанныеФормы не всегда автоматически устанавливает признак того, что форма изменена. Чтобы пользователь не закрыл документ без сохранения изменений, всегда явно прописывайте ЭтаФорма.Модифицированность = Истина;.

2. Обработчики событий ПриИзменении. Помните, что при программной подмене данных формы через ЗначениеВДанныеФормы или КопироватьДанныеФормы не вызываются клиентские события элементов управления (такие как ПриИзменении). Если у вас в документе есть сложная логика пересчета итогов или налогов, завязанная на эти события, вам придется вызвать соответствующий серверный метод пересчета вручную после обновления данных.

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

Резюме

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

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

← На главную