При разработке внешних обработок заполнения для управляемых форм (УФ) программисты часто сталкиваются с проблемой синхронизации данных. Типичный сценарий: обработка запущена из формы документа в режиме ОткрытьФорму, она вносит изменения в объект (с записью или без), но в исходной форме документа эти изменения не отображаются автоматически. Стандартный метод ОповеститьОбИзменении() в данном случае обновляет лишь списки и кэш, но не заставляет открытую форму перечитать данные.
В этой статье мы разберем несколько эффективных способов решения этой задачи, проанализируем механизмы работы платформы 1С:Предприятие 8.3 и выберем оптимальные подходы для различных ситуаций.
Если ваша внешняя обработка записывает объект в базу данных, то основной задачей становится команда форме документа перечитать эти данные из информационной базы. Рассмотрим ситуацию, когда нам нужно найти форму, из которой была вызвана обработка, и вызвать у нее метод Прочитать().
Разберем пример кода, который можно использовать в модуле формы внешней обработки на клиенте. Мы будем использовать перебор открытых окон для поиска нужной формы:
&НаКлиенте
Процедура ОбновитьФормуДокумента()
// Получаем массив всех открытых окон приложения
ОткрытыеОкна = ПолучитьОкна();
Для Каждого Окно Из ОткрытыеОкна Цикл
// Проверяем, является ли окно основным и не является ли оно самой обработкой
СодержимоеОкна = Окно.Содержимое;
Для Каждого ЭлементСодержимого Из СодержимоеОкна Цикл
// Пытаемся идентифицировать форму документа по заголовку или типу данных
// В данном примере проверим наличие ссылки в объекте формы
Попытка
Если ЭлементСодержимого.Объект.Ссылка = Объект.СсылкаНаДокумент Тогда
// Вызываем метод Прочитать() для обновления данных из БД
ЭлементСодержимого.Прочитать();
Возврат; // Прекращаем поиск, если форма найдена
КонецЕсли;
Исключение
// Пропускаем формы, у которых нет реквизита Объект.Ссылка
КонецПопытки;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Важный нюанс: метод Прочитать() полностью перезаполняет реквизит Объект формы данными из базы. Это означает, что любые несохраненные изменения, внесенные пользователем в форму документа вручную до запуска обработки, будут потеряны.
Часто бизнес-процесс требует, чтобы внешняя обработка только подготовила данные, а окончательное решение о записи документа принял пользователь. Это наиболее гибкий и безопасный подход. Рассмотрим, как передать данные из обработки напрямую в форму-владелец без обращения к базе данных.
Для реализации этого метода обработка должна быть открыта с указанием владельца (формы документа). Рассмотрим алгоритм действий:
КопироватьДанныеФормы().Пример реализации в форме внешней обработки:
&НаКлиенте
Процедура ЗаполнитьБезЗаписи()
// Проверяем, что у обработки есть владелец (форма документа)
Если ВладелецФормы = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем текущее состояние объекта из формы документа
ДанныеДокумента = ВладелецФормы.Объект;
// Вызываем серверную процедуру обработки для заполнения данных
ЗаполнитьНаСервере(ДанныеДокумента);
// Копируем измененные данные обратно в форму документа
КопироватьДанныеФормы(ДанныеДокумента, ВладелецФормы.Объект);
// Обязательно устанавливаем флаг модифицированности, чтобы пользователь видел изменения
ВладелецФормы.Модифицированность = Истина;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьНаСервере(ДанныеФормыДокумента)
// Преобразуем данные формы в объект для удобства работы
ДокОбъект = ДанныеФормыВЗначение(ДанныеФормыДокумента, Тип("ДокументОбъект.ПриемНаРаботу"));
// Выполняем алгоритм заполнения
ДокОбъект.Комментарий = "Заполнено внешней обработкой " + ТекущаяДата();
// ... заполнение табличных частей ...
// Преобразуем обратно в данные формы
ЗначениеВДанныеФормы(ДокОбъект, ДанныеФормыДокумента);
КонецПроцедуры
Если мы не хотим перебирать все окна через ПолучитьОкна(), существует более "чистый" способ получить ссылку на уже открытую форму конкретного объекта. Система 1С позволяет получить форму, передав в параметрах Ключ (ссылку на объект). Если форма этого объекта уже открыта, платформа вернет именно её, а не создаст новую.
Проанализируем этот подход:
&НаКлиенте
Процедура ОбновитьКонкретнуюФорму(СсылкаНаДокумент)
// Параметр Ключ указывает на конкретный объект в базе
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
// Имя формы должно соответствовать полному пути в конфигурации
ИмяФормы = "Документ.ПриемНаРаботу.Форма.ФормаДокумента";
// Получаем форму. Если она открыта, вернется существующий экземпляр
ФормаДокумента = ПолучитьФорму(ИмяФормы, ПараметрыФормы);
Если ФормаДокумента.Открыта() Тогда
ФормаДокумента.Прочитать();
КонецЕсли;
КонецПроцедуры
Выясним причину, по которой стандартное оповещение часто оказывается бесполезным в данной задаче. Метод ОповеститьОбИзменении(Ссылка) предназначен для уведомления системы о том, что данные в базе данных изменились. Его основная роль:
Однако, согласно логике платформы, уже открытая форма объекта считается интерактивной зоной работы пользователя. Система намеренно не обновляет её автоматически, так как у пользователя могут быть свои несохраненные правки, которые затрутся при принудительном обновлении. Именно поэтому для обновления открытой формы требуется явный вызов метода Прочитать() или манипуляция через КопироватьДанныеФормы().
В современных конфигурациях (например, ЗУП 3.1 КОРП), внешние обработки заполнения обычно подключаются через механизм Дополнительных отчетов и обработок. В этом случае взаимодействие происходит через стандартные интерфейсы БСП.
Если обработка запускается с типом "ВызовКлиентскогоМетода", в процедуру ВыполнитьКоманду передается параметр ПараметрыВыполнения. Рассмотрим, как обратиться к форме из этого контекста:
&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
// В некоторых версиях БСП форма-инициатор доступна напрямую
Если ПараметрыВыполнения.Свойство("ЭтаФорма") Тогда
ФормаДокумента = ПараметрыВыполнения.ЭтаФорма;
// Работаем с ФормаДокумента.Объект
КонецЕсли;
КонецПроцедуры
Резюмируем: для качественного обновления формы используйте КопироватьДанныеФормы, если хотите оставить выбор записи за пользователем, или Форма.Прочитать(), если запись производится программно в коде обработки. Поиск формы лучше всего выполнять через ПолучитьФорму с параметром Ключ, так как это наиболее надежный способ идентификации нужного окна в многопользовательской среде.