При разработке в среде 1С:Предприятие 8.3 (особенно в управляемом приложении) программисты часто сталкиваются с необходимостью асинхронного взаимодействия с пользователем. Основным инструментом для этого долгое время служил объект ОписаниеОповещения. Однако при его использовании новички и даже опытные разработчики иногда натыкаются на ошибку: платформа «не видит» процедуру, которую должна вызвать. В этой статье мы подробно разберем, почему это происходит, как правильно оформить клиентский обработчик и какие современные альтернативы существуют.
Рассмотрим стандартную ситуацию: нам нужно открыть форму для ввода данных (например, уточнения количества товара) и по завершении выполнить какой-то код на клиенте, чтобы обновить показатели в основной форме. Мы создаем объект ОписаниеОповещения, указываем имя процедуры и модуль, но при попытке вызова получаем системную ошибку о том, что метод не обнаружен. Проанализируем типичный ошибочный код:
// Вызов открытия формы
ПараметрыТовара = Новый Структура("Артикул, Количество", "001", 10);
Оповещение = Новый ОписаниеОповещения("ОбновитьПоказатели", ЭтаФорма, ПараметрыТовара);
ОткрытьФорму("ОбщаяФорма.ЗапросКоличества", , , , , , Оповещение, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
Если процедура ОбновитьПоказатели объявлена просто как &НаКлиенте, платформа выдаст ошибку. Выясним причину: механизм оповещений работает через программный интерфейс платформы, который обращается к модулю формы «со стороны». Для того чтобы внешнее событие (закрытие окна) смогло достучаться до кода внутри модуля, этот код должен быть открыт для внешнего вызова.
Главным условием работоспособности клиентского оповещения является наличие ключевого слова Экспорт. Без него процедура считается приватной внутри модуля, и менеджер оповещений платформы не имеет к ней доступа.
Правильное объявление процедуры в модуле формы должно выглядеть следующим образом:
&НаКлиенте
Процедура ОбновитьПоказатели(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат; // Пользователь закрыл окно без сохранения
КонецЕсли;
// Работаем с данными
ТекущийАртикул = ДополнительныеПараметры.Артикул;
НовоеКоличество = Результат.Количество;
// Логика обновления строк документа на клиенте
ОбновитьСтрокуВДокументе(ТекущийАртикул, НовоеКоличество);
КонецПроцедуры
Обратите внимание, что автор исходного вопроса использовал Функция. Технически платформа проглотит это, но хорошим тоном и стандартом разработки 1С считается использование именно Процедура, так как возвращаемое значение всё равно никуда не передается.
Давайте проанализируем структуру конструктора Новый ОписаниеОповещения, чтобы понимать, как передавать данные между вызовами:
ЭтаФорма, если обработчик находится в текущей форме. Если обработчик в общем модуле — передается сам общий модуль.Чтобы всё «взлетело», недостаточно просто добавить Экспорт. Проанализируем еще несколько жестких требований платформы:
1. Количество параметров. Процедура-обработчик обязана принимать ровно два параметра. Даже если вы не собираетесь использовать ДополнительныеПараметры, они должны быть в заголовке процедуры. В противном случае возникнет ошибка времени выполнения.
2. Контекст исполнения. Если вы вызываете оповещение из модуля команды, вы не можете передать ЭтаФорма в качестве модуля. В этом случае обработчик должен располагаться либо в самом модуле команды (с Экспорт), либо в общем модуле, у которого стоят флаги Клиент (управляемое приложение) и Вызов сервера (если нужно).
3. Отладка. Помните, что при срабатывании оповещения стек вызовов обрывается. Вы не увидите в отладчике ту процедуру, из которой открывали форму. Это особенность асинхронности — выполнение кода «засыпает» и просыпается уже в новой точке.
Начиная с версии платформы 8.3.18, фирма «1С» представила более элегантный механизм — асинхронные функции. Вместо того чтобы дробить код на «вызывающий» и «обрабатывающий», мы можем писать линейный код. Рассмотрим, как это упрощает жизнь:
&НаКлиенте
Асинх Процедура ИзменитьКоличествоНаКлиенте()
ПараметрыФормы = Новый Структура("ТекущееКоличество", 10);
// Вместо ОписанияОповещения используем Ждать
Результат = Ждать ОткрытьФормуАсинх("ОбщаяФорма.ЗапросКоличества", ПараметрыФормы);
Если Результат <> Неопределено Тогда
// Код выполняется здесь же, сохраняя доступ к локальным переменным!
ОбновитьПоказателиНаСервере(Результат.Количество);
КонецЕсли;
КонецПроцедуры
Использование оператора Ждать и метода ОткрытьФормуАсинх избавляет от необходимости плодить экспортные процедуры и вручную пробрасывать структуру дополнительных параметров. Это делает код чище и понятнее для поддержки.
Если вы работаете на версиях платформы ниже 8.3.18 или поддерживаете старый код, помните золотые правила ОписаниеОповещения:
&НаКлиенте).Соблюдение этих простых правил убережет вас от трудноуловимых ошибок «Метод не найден» и позволит строить отзывчивые интерфейсы с блокировкой только нужных участков программы.