При переходе на новые релизы платформы 1С:Предприятие 8.3 (в частности, на ветку 8.3.15 и выше) разработчики часто сталкиваются с неожиданным изменением поведения стандартных функций. Одной из таких проблем является некорректная работа асинхронного метода ПоказатьВопрос. Вместо ожидаемого значения, указанного в параметрах, или системного значения Таймаут, процедура-обработчик получает КодВозвратаДиалога.Отмена. Разберем детально, почему это происходит, является ли это ошибкой платформы и как написать универсальный код, устойчивый к таким изменениям.
Для начала проанализируем параметры метода ПоказатьВопрос, чтобы понять, как система должна себя вести согласно документации. Синтаксис метода выглядит следующим образом:
ПоказатьВопрос(<ОписаниеОповещенияОЗавершении>, <ТекстВопроса>, <Кнопки>, <Таймаут>, <КнопкаПоУмолчанию>, <Заголовок>, <КнопкаТаймаута>)
Многие разработчики, привыкшие к старой синхронной функции Вопрос, допускают ошибку в трактовке последнего параметра — КнопкаТаймаута. Проанализируем, что говорит нам Синтаксис-помощник:
КодВозвратаДиалога.Таймаут.Таким образом, если вы ожидаете, что при закрытии окна через 5 секунд в переменную Результат попадет КодВозвратаДиалога.ОК только потому, что вы указали эту кнопку в параметре КнопкаТаймаута, — это не совсем верно для асинхронных вызовов в новых режимах совместимости.
Выясним причину разного поведения платформы на разных базах. Поведение функции ПоказатьВопрос критически зависит от свойства конфигурации «Режим совместимости»:
КодВозвратаДиалога.Таймаут. Это сделано для того, чтобы программист мог четко отличить осознанный выбор пользователя от автоматического закрытия окна.Если в вашей базе установлен современный режим совместимости, а платформа возвращает КодВозвратаДиалога.Отмена, мы имеем дело либо с логической ошибкой в коде, либо с багом конкретного релиза платформы.
Рассмотрим ситуацию, описанную пользователями: на релизе 8.3.15.1489 при асинхронном вызове в «чистой» базе (без режима совместимости) вместо Таймаут возвращается Отмена. Это действительно признанный баг некоторых сборок платформы 8.3.15 и 8.3.16. Система ошибочно интерпретирует завершение ожидания как принудительное закрытие окна (аналогично нажатию на «крестик» или клавишу Esc), что и порождает возврат Отмена.
Это особенно часто проявляется в следующих случаях:
СписокЗначений.Чтобы ваша программа работала корректно независимо от версии платформы и наличия в ней ошибок, рекомендуется использовать «защитный» стиль кодирования. Рассмотрим пример правильной реализации вызова и обработки результата.
Сначала подготовим и вызовем вопрос:
Процедура ЗадатьВопросПользователю()
Обработчик = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект);
ТекстВопроса = "Выполнить регламентную операцию сейчас?";
СписокКнопок = Новый СписокЗначений;
СписокКнопок.Добавить(КодВозвратаДиалога.Да, "Выполнить");
СписокКнопок.Добавить(КодВозвратаДиалога.Нет, "Пропустить");
// Указываем таймаут 10 секунд
// На кнопке "Да" будет отображаться обратный отсчет
ПоказатьВопрос(Обработчик, ТекстВопроса, СписокКнопок, 10, КодВозвратаДиалога.Нет,, КодВозвратаДиалога.Да);
КонецПроцедуры
Теперь проанализируем ситуацию в процедуре обработки. Нам нужно учесть, что по таймауту может прийти как Таймаут (по стандарту), так и Отмена (из-за бага), так и конкретное значение кнопки (в старых режимах).
Процедура ПослеВопроса(Результат, ДополнительныеПараметры) Экспорт
// Определяем логику: если пользователь ничего не нажал (таймаут или ошибка),
// мы должны выполнить действие по умолчанию.
ДействиеВыполнено = Ложь;
Если Результат = КодВозвратаДиалога.Да Тогда
ДействиеВыполнено = Истина;
ИначеЕсли Результат = КодВозвратаДиалога.Таймаут
ИЛИ Результат = КодВозвратаДиалога.Отмена Тогда
// Обработка случая, когда пользователь проигнорировал окно
// или сработал баг платформы 8.3.15
Сообщить("Действие отменено по таймауту или закрыто принудительно.");
КонецЕсли;
Если ДействиеВыполнено Тогда
// Вызов основной логики
ВыполнитьОперацию();
КонецЕсли;
КонецПроцедуры
Если вы обнаружили, что в вашей системе ПоказатьВопрос работает не по инструкции, выполните следующие шаги:
Отмена вместо Таймаут были исправлены.КодВозвратаДиалога.Таймаут может вообще не приходить.Результат = Неопределено (если это возможно в веб-клиенте) и Результат = КодВозвратаДиалога.Отмена как эквивалент отказа от выбора, если это не критично для бизнес-логики.Подводя итог, можно сказать, что проблема в 8.3.15 — это совокупность изменения архитектуры (переход на обязательный возврат Таймаут) и досадной ошибки реализации в конкретных сборках. Проектируйте свои оповещения так, чтобы они были готовы к любому из этих вариантов развития событий.