Разработка и Конфигурация · 10 мин
1С управляемые формы: как задать вопрос пользователю
Как задать вопрос пользователю в управляемых формах 1С: процедура ПоказатьВопрос, режимы диалога, обработка ответа, переход с модального Вопрос(), примеры кода.
В управляемых формах 1С нельзя использовать привычный по обычным формам метод Вопрос() — он работает в модальном режиме, который запрещён в веб-клиенте и не рекомендован в тонком клиенте. Вместо него применяется асинхронный метод ПоказатьВопрос(), который не останавливает выполнение кода, а передаёт результат в отдельную процедуру-обработчик через механизм ОписаниеОповещения.
Такой подход требует другого стиля мышления: код после вопроса не пишется «ниже по тексту», а выносится в отдельную процедуру, которая сработает после ответа пользователя. Это главная сложность для тех, кто переходит с обычных форм, и основная причина ошибок вида «код выполняется раньше ответа».
Ниже разобраны синтаксис ПоказатьВопрос(), режимы диалога, передача дополнительных параметров в обработчик, типичные сценарии (подтверждение удаления, выбор из вариантов) и способ быстро сделать вопрос модальным, если доработка должна быть минимальной.
Почему нельзя использовать модальный Вопрос()
Метод Вопрос() открывает модальное окно и останавливает выполнение кода до ответа пользователя. В управляемых формах такой режим ограничен: веб-клиент в принципе не поддерживает модальные вызовы, а в тонком клиенте их использование зависит от режима модальности, заданного в свойствах конфигурации.
Если конфигурация работает в режиме «Не использовать» модальность, вызов Вопрос() вызовет ошибку выполнения. Если режим разрешает модальность — код заработает, но решение будет непереносимым в веб-клиент и уязвимым при смене настроек. Поэтому правильный путь — сразу писать асинхронно через ПоказатьВопрос().
Синтаксис ПоказатьВопрос и минимальный пример
Метод вызывается у объекта ОписаниеОповещения не вызывается — наоборот, оповещение передаётся первым параметром в вопрос:
&НаКлиенте
Процедура УдалитьСтроку(Команда)
Оповещение = Новый ОписаниеОповещения("УдалитьСтрокуЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение,
"Удалить выбранную строку?",
РежимДиалогаВопрос.ДаНет,
20, // таймаут в секундах
КодВозвратаДиалога.Нет);
КонецПроцедуры
&НаКлиенте
Процедура УдалитьСтрокуЗавершение(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// действие при подтверждении
КонецЕсли;
КонецПроцедуры
Ключевые параметры: текст вопроса, режим диалога (набор кнопок), таймаут в секундах (0 — без ограничения), кнопка по умолчанию. Процедура-обработчик обязательно объявляется с ключевым словом Экспорт, иначе платформа не сможет её вызвать, и должна находиться в клиентском контексте.
Режимы диалога и коды возврата
Набор кнопок определяется перечислением РежимДиалогаВопрос, а ответ пользователя приходит как значение КодВозвратаДиалога. Сопоставление важно проверять явно, а не полагаться на «любой ответ».
| Режим диалога | Кнопки | Возможные коды возврата |
|---|---|---|
| ДаНет | Да, Нет | Да, Нет |
| ДаНетОтмена | Да, Нет, Отмена | Да, Нет, Отмена |
| ОК | ОК | ОК |
| ОКОтмена | ОК, Отмена | ОК, Отмена |
| ПовторитьОтмена | Повторить, Отмена | Повторить, Отмена |
| ПрерватьПовторитьПропустить | Прервать, Повторить, Пропустить | Прервать, Повторить, Пропустить |
Если пользователь закрыл окно крестиком или сработал таймаут, возвращается код кнопки по умолчанию либо КодВозвратаДиалога.Таймаут при установленном таймауте. Это стоит учитывать: безопаснее назначать кнопкой по умолчанию «отказное» действие (Нет, Отмена), чтобы случайное закрытие не запускало необратимую операцию.
Передача дополнительных параметров в обработчик
Часто в обработчике нужны данные, известные в момент постановки вопроса: ссылка на удаляемый объект, номер строки, выбранное значение. Их передают третьим параметром конструктора ОписаниеОповещения — обычно структурой:
ДопПараметры = Новый Структура("СсылкаНаДокумент", ТекущийДокумент);
Оповещение = Новый ОписаниеОповещения("ПослеВопросаОПроведении", ЭтотОбъект, ДопПараметры);
ПоказатьВопрос(Оповещение, "Провести документ?", РежимДиалогаВопрос.ДаНет);
В обработчике эти данные доступны через второй параметр: ДополнительныеПараметры.СсылкаНаДокумент. Такой приём устраняет необходимость хранить промежуточные значения в реквизитах формы и делает код устойчивым к повторным вызовам.
- 1Создайте клиентскую процедуру команды или события, откуда задаётся вопрос
- 2Сформируйте ОписаниеОповещения с именем будущего обработчика и при необходимости структурой дополнительных параметров
- 3Вызовите ПоказатьВопрос с текстом, режимом диалога, таймаутом и кнопкой по умолчанию
- 4Создайте экспортную клиентскую процедуру-обработчик с параметрами Результат и ДополнительныеПараметры
- 5Перенесите логику, зависящую от ответа, в обработчик с проверкой КодВозвратаДиалога
- 6Проверьте поведение при отказе, закрытии окна и срабатывании таймаута
Типичные сценарии использования
Подтверждение удаления или записи
Самый частый случай — спросить «Удалить?» перед необратимым действием. Кнопкой по умолчанию ставят Нет, действие выполняют только при явном Да. Для удаления помеченных объектов удобно дополнительно выводить в тексте вопроса наименование объекта, чтобы пользователь видел, что именно удаляет.
Вопрос перед закрытием формы
Если форма содержит несохранённые изменения, вопрос задают в обработчике ПередЗакрытием. Здесь есть особенность: закрытие нужно сначала отменить (Отказ = Истина), а после положительного ответа вызвать Закрыть() повторно, предварительно установив признак, что вопрос уже задан, иначе цикл повторится.
Свои варианты ответов через СписокЗначений
Если стандартных кнопок не хватает, вместо режима диалога передают СписокЗначений с произвольными кнопками: например «Сохранить», «Не сохранять», «Отмена». В качестве значения элемента списка указывают код возврата, который придёт в обработчик.
Способы задать вопрос
Рекомендуемый вариант для управляемых форм. Работает в тонком, толстом и веб-клиенте, требует разнесения кода на две процедуры
Простой код, но работает только при разрешённой модальности и недоступен в веб-клиенте. Подходит лишь как временное решение в закрытом тонком клиенте
Подходит, когда выбора нет и нужно просто сообщить факт; вопросом не является, ответа не возвращает
Как проверить результат и типичные ошибки
После внедрения проверьте все ветки: согласие, отказ, закрытие окна, таймаут. Убедитесь, что при отказе не выполняется ни одно действие из «положительной» ветки — например, документ не записывается и не проводится.
Характерные ошибки: код после ПоказатьВопрос продолжает выполняться сразу, не дожидаясь ответа (нужно переносить его в обработчик); обработчик без Экспорт; сравнение результата со строкой «Да» вместо КодВозвратаДиалога.Да; использование контекстной серверной процедуры как обработчика. Ещё одна ловушка — вопрос в цикле: при обходе таблицы вопросы «наслаиваются», поэтому цикл перестраивают на рекурсивный вызов из обработчика.
Как проверить результат
Выполняется защищаемое действие (удаление, проведение)
Действие не выполняется или выполняется дважды
Ничего не происходит, форма остаётся в исходном состоянии
Действие всё равно выполняется
Срабатывает безопасный вариант по умолчанию
Запускается необратимая операция
Диалог открывается, обработчик вызывается
Ошибка модальности или молчание обработчика
Для отладки удобно временно добавить в обработчик вывод значения Результат через Сообщить() — это позволяет увидеть, какой именно код возврата приходит при каждом способе закрытия диалога, и скорректировать условия.
Что важно запомнить
В управляемых формах вопрос задаётся только асинхронно: ПоказатьВопрос + ОписаниеОповещения + экспортная клиентская процедура-обработчик. Логика после ответа живёт в обработчике, кнопка по умолчанию — безопасная, результат сравнивается с КодВозвратаДиалога.
Частые вопросы
Можно ли дождаться ответа и продолжить код в той же процедуре?
В асинхронной модели — нет: ПоказатьВопрос не блокирует выполнение. Продолжение оформляется отдельной процедурой-обработчиком. Если требуется последовательность из нескольких вопросов, каждый следующий задаётся из обработчика предыдущего, образуя цепочку.
Как задать вопрос из серверной процедуры?
Напрямую никак — диалог с пользователем возможен только на клиенте. Серверная процедура возвращает клиенту признак необходимости вопроса и нужные данные, а клиентский код задаёт вопрос и по ответу вызывает следующий серверный метод.
Что вернётся в обработчик при таймауте?
Если таймаут установлен и истёк, в обработчик приходит КодВозвратаДиалога.Таймаут. Это значение стоит обрабатывать явно или гарантировать, что оно не совпадает с веткой согласия, иначе бездействие пользователя будет равнозначно подтверждению.
Как сделать свои надписи на кнопках?
Передайте вместо РежимДиалогаВопрос объект СписокЗначений: каждый элемент — это кнопка, представление элемента становится надписью, а значение — кодом, который придёт в обработчик. Например, кнопки «В файл» и «На печать» для выбора способа вывода отчёта.
Работает ли ПоказатьВопрос в веб-клиенте?
Да, асинхронные методы специально разработаны для совместимости с веб-клиентом. Именно поэтому ПоказатьВопрос — единственный корректный способ задать вопрос в конфигурациях, доступных через браузер.
Чем заменить Вопрос() при конвертации обычных форм?
Каждый вызов Вопрос() разбивается на две части: исходная процедура формирует ОписаниеОповещения и вызывает ПоказатьВопрос, а весь код, зависящий от ответа, переносится в новую экспортную клиентскую процедуру, указанную в оповещении. Контекст (ссылки, строки) передаётся через структуру дополнительных параметров.