При разработке расширений для 1С программисты часто сталкиваются с ситуацией, когда стандартная аннотация &После (или &After) на команду формы работает не так, как ожидается. Если основная команда запускает длительную операцию или фоновое задание через механизм оповещений, код расширения выполняется сразу после запуска процесса, но до его фактического завершения и внесения изменений в данные. Рассмотрим, почему это происходит и как правильно "поймать" момент завершения работы фонового задания.
Проанализируем механику работы управляемых форм. Когда пользователь нажимает на кнопку, вызывается клиентская процедура команды. Если внутри этой процедуры реализован запуск фонового задания (например, через механизмы БСП ДлительныеОперацииКлиент), платформа выполняет следующие шаги:
ОписаниеОповещения (callback-функцию), которая должна выполниться по возвращении результата.Поскольку процедура команды технически завершена (она лишь "дала старт" заданию), расширение с аннотацией &После срабатывает незамедлительно. В этот момент фоновое задание на сервере может еще даже не начать выполняться. Попытки использовать задержки через пустые циклы или иные методы "ожидания" внутри расширения бесполезны, так как они блокируют основной поток интерфейса, не давая платформе обработать результат фонового задания.
Это самый правильный и надежный метод. Нам нужно найти не саму команду, а ту процедуру, которая указана в качестве обработчика завершения в объекте ОписаниеОповещения. Выясним, как это сделать.
Разберем пример типичного кода команды, которую нам нужно расширить:
&НаКлиенте
Процедура КомандаВыполнитьРассчитать(Команда)
ПараметрыЗадания = Новый Структура;
// ... заполнение параметров ...
Оповещение = Новый ОписаниеОповещения("ПослеЗавершенияРассчета", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершения(Задание, Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗавершенияРассчета(Результат, ДополнительныеПараметры) Экспорт
// Здесь происходит обработка данных после фонового задания
КонецПроцедуры
В данном случае расширять нужно не КомандаВыполнитьРассчитать, а процедуру ПослеЗавершенияРассчета. Именно в ней мы применяем аннотацию &После. Посмотрим на код расширения:
&После("ПослеЗавершенияРассчета")
Процедура Расш1_ПослеЗавершенияРассчета(Результат, ДополнительныеПараметры)
// Наш код выполнится строго после того, как отработает стандартная логика
// обработки результата фонового задания.
Сообщить("Все изменения применены, выполняем дополнительную логику!");
КонецПроцедуры
Важный нюанс: Процедура-обработчик в основной конфигурации должна иметь экспортное объявление (Экспорт), чтобы расширение могло к ней корректно привязаться.
Иногда процедура завершения является общей или вызывается динамически, и прямое расширение &После применить сложно. В такой ситуации мы можем применить метод "перехвата" самого описания оповещения. Проанализируем, как это реализовать через аннотацию &Вместо на саму команду.
Рассмотрим алгоритм действий:
&Вместо для процедуры команды формы.ОписаниеОповещения, которое указывает на нашу процедуру в расширении.Пример реализации перехвата:
&Вместо("КомандаВыполнитьРассчитать")
Процедура Расш1_КомандаВыполнитьРассчитать(Команда)
// Копируем логику подготовки (или вызываем ПродолжитьВызов, если структура позволяет)
// Но меняем создание Оповещения:
ПараметрыОповещения = Новый Структура("ОригинальноеОповещение", "ПослеЗавершенияРассчета");
МоеОповещение = Новый ОписаниеОповещения("Расш1_МойОбработчикЗавершения", ЭтотОбъект, ПараметрыОповещения);
// Запускаем операцию с нашим оповещением
// ... (код запуска задания) ...
КонецПроцедуры
&НаКлиенте
Процедура Расш1_МойОбработчикЗавершения(Результат, ДополнительныеПараметры) Экспорт
// Сначала вызываем стандартный обработчик (если нужно)
// Для этого можно использовать программный вызов или заранее скопированную логику
// Затем выполняем свои действия
ВыполнитьДополнительныеДействияПослеФонового();
КонецПроцедуры
Если вмешательство в callback-функции кажется слишком сложным или структура кода основной конфигурации крайне запутана, можно использовать "ленивый" метод с обработчиком ожидания. Этот метод позволяет проверить состояние формы через небольшие промежутки времени.
Разберем, как это работает:
&После подключаем однократный обработчик ожидания.Пример кода:
&После("КомандаВыполнитьРассчитать")
Процедура Расш1_КомандаВыполнитьРассчитать_После(Команда)
// Запускаем проверку через 0.1 секунды
ПодключитьОбработчикОжидания("Расш1_ПроверитьЗавершениеФонового", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура Расш1_ПроверитьЗавершениеФонового() Экспорт
// Проверяем, изменился ли реквизит, который заполняет фоновое задание
Если Объект.СтатусЗадания = ПредопределенноеЗначение("Перечисление.Статусы.Завершено") Тогда
// Выполняем наш код
ЗавершитьДополнительнуюОбработку();
Иначе
// Если еще не готово, пробуем еще раз через 0.2 сек
ПодключитьОбработчикОжидания("Расш1_ПроверитьЗавершениеФонового", 0.2, Истина);
КонецЕсли;
КонецПроцедуры
Внимание: Этот метод считается менее надежным, так как он создает лишнюю нагрузку на клиентское приложение и может привести к "зацикливанию", если фоновое задание завершится с ошибкой и статус не обновится. Используйте его только в крайних случаях.
Для выбора оптимального пути проанализируем структуру типового решения:
ОписаниеОповещения с указанием конкретной экспортной процедуры в этой же форме — используйте Решение 1 (расширение этой процедуры).&Вместо на команду).ДлительныеОперации, обратите внимание на процедуру ПриЗавершенииВыполнения или аналогичные, которые вызываются в форме ожидания.В большинстве современных конфигураций на базе БСП (ERP, УТ 11, ЗУП 3) используется стандартизированный метод ожидания. Ищите вызовы ДлительныеОперацииКлиент.ОжидатьЗавершения и расширяйте процедуру, передаваемую во втором параметре этого метода. Это обеспечит стабильную работу вашего кода после того, как все данные с сервера будут получены и отображены на форме пользователя.