Почему ПоказатьВопрос возвращает «Отмена» вместо «Таймаут» и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При переходе на новые релизы платформы 1С:Предприятие 8.3 (в частности, на ветку 8.3.15 и выше) разработчики часто сталкиваются с неожиданным изменением поведения стандартных функций. Одной из таких проблем является некорректная работа асинхронного метода ПоказатьВопрос. Вместо ожидаемого значения, указанного в параметрах, или системного значения Таймаут, процедура-обработчик получает КодВозвратаДиалога.Отмена. Разберем детально, почему это происходит, является ли это ошибкой платформы и как написать универсальный код, устойчивый к таким изменениям.

Разбор синтаксиса и типичные заблуждения

Для начала проанализируем параметры метода ПоказатьВопрос, чтобы понять, как система должна себя вести согласно документации. Синтаксис метода выглядит следующим образом:

ПоказатьВопрос(<ОписаниеОповещенияОЗавершении>, <ТекстВопроса>, <Кнопки>, <Таймаут>, <КнопкаПоУмолчанию>, <Заголовок>, <КнопкаТаймаута>)

Многие разработчики, привыкшие к старой синхронной функции Вопрос, допускают ошибку в трактовке последнего параметра — КнопкаТаймаута. Проанализируем, что говорит нам Синтаксис-помощник:

  1. Параметр КнопкаТаймаута — он лишь определяет кнопку, на которой будет отображаться визуальный счетчик секунд. Он не гарантирует, что именно это значение вернется в обработчик оповещения.
  2. Результат вопроса — в случае закрытия диалога по истечении времени асинхронный метод должен возвращать специальное значение КодВозвратаДиалога.Таймаут.

Таким образом, если вы ожидаете, что при закрытии окна через 5 секунд в переменную Результат попадет КодВозвратаДиалога.ОК только потому, что вы указали эту кнопку в параметре КнопкаТаймаута, — это не совсем верно для асинхронных вызовов в новых режимах совместимости.

Влияние режима совместимости конфигурации

Выясним причину разного поведения платформы на разных базах. Поведение функции ПоказатьВопрос критически зависит от свойства конфигурации «Режим совместимости»:

Если в вашей базе установлен современный режим совместимости, а платформа возвращает КодВозвратаДиалога.Отмена, мы имеем дело либо с логической ошибкой в коде, либо с багом конкретного релиза платформы.

Анализ бага в релизах 8.3.15

Рассмотрим ситуацию, описанную пользователями: на релизе 8.3.15.1489 при асинхронном вызове в «чистой» базе (без режима совместимости) вместо Таймаут возвращается Отмена. Это действительно признанный баг некоторых сборок платформы 8.3.15 и 8.3.16. Система ошибочно интерпретирует завершение ожидания как принудительное закрытие окна (аналогично нажатию на «крестик» или клавишу Esc), что и порождает возврат Отмена.

Это особенно часто проявляется в следующих случаях:

  1. Использование веб-клиента в браузере, где фокус окна был потерян.
  2. Работа в тонком клиенте при специфических настройках операционной системы.
  3. Использование нестандартных наборов кнопок через СписокЗначений.

Как написать надежный обработчик: практический пример

Чтобы ваша программа работала корректно независимо от версии платформы и наличия в ней ошибок, рекомендуется использовать «защитный» стиль кодирования. Рассмотрим пример правильной реализации вызова и обработки результата.

Сначала подготовим и вызовем вопрос:


Процедура ЗадатьВопросПользователю()
    
    Обработчик = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект);
    ТекстВопроса = "Выполнить регламентную операцию сейчас?";
    
    СписокКнопок = Новый СписокЗначений;
    СписокКнопок.Добавить(КодВозвратаДиалога.Да, "Выполнить");
    СписокКнопок.Добавить(КодВозвратаДиалога.Нет, "Пропустить");
    
    // Указываем таймаут 10 секунд
    // На кнопке "Да" будет отображаться обратный отсчет
    ПоказатьВопрос(Обработчик, ТекстВопроса, СписокКнопок, 10, КодВозвратаДиалога.Нет,, КодВозвратаДиалога.Да);
    
КонецПроцедуры

Теперь проанализируем ситуацию в процедуре обработки. Нам нужно учесть, что по таймауту может прийти как Таймаут (по стандарту), так и Отмена (из-за бага), так и конкретное значение кнопки (в старых режимах).


Процедура ПослеВопроса(Результат, ДополнительныеПараметры) Экспорт
    
    // Определяем логику: если пользователь ничего не нажал (таймаут или ошибка), 
    // мы должны выполнить действие по умолчанию.
    
    ДействиеВыполнено = Ложь;
    
    Если Результат = КодВозвратаДиалога.Да Тогда
        
        ДействиеВыполнено = Истина;
        
    ИначеЕсли Результат = КодВозвратаДиалога.Таймаут 
        ИЛИ Результат = КодВозвратаДиалога.Отмена Тогда
        
        // Обработка случая, когда пользователь проигнорировал окно
        // или сработал баг платформы 8.3.15
        Сообщить("Действие отменено по таймауту или закрыто принудительно.");
        
    КонецЕсли;
    
    Если ДействиеВыполнено Тогда
        // Вызов основной логики
        ВыполнитьОперацию();
    КонецЕсли;

КонецПроцедуры

Рекомендации по исправлению

Если вы обнаружили, что в вашей системе ПоказатьВопрос работает не по инструкции, выполните следующие шаги:

  1. Проверьте версию платформы. Если вы используете релизы ниже 8.3.15.1747 или 8.3.16.1148, рекомендуется обновиться. В более свежих сборках ошибки с возвратом Отмена вместо Таймаут были исправлены.
  2. Проверьте режим совместимости. Если ваша конфигурация находится на поддержке и режим совместимости «заморожен» на версии 8.3.12, будьте готовы к тому, что КодВозвратаДиалога.Таймаут может вообще не приходить.
  3. Используйте универсальную проверку. В коде всегда обрабатывайте ситуацию Результат = Неопределено (если это возможно в веб-клиенте) и Результат = КодВозвратаДиалога.Отмена как эквивалент отказа от выбора, если это не критично для бизнес-логики.
  4. Избегайте важной логики в таймаутах. Как отмечали участники обсуждения, важные действия (например, проведение документов) лучше выносить в регламентные задания, а не полагаться на автоматическое закрытие вопроса у пользователя, который мог просто отойти от рабочего места.

Подводя итог, можно сказать, что проблема в 8.3.15 — это совокупность изменения архитектуры (переход на обязательный возврат Таймаут) и досадной ошибки реализации в конкретных сборках. Проектируйте свои оповещения так, чтобы они были готовы к любому из этих вариантов развития событий.

← На главную