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