Почему некорректно работает метод Вопрос() и зависает интерфейс в 1С:Предприятие 8.3

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 начинающие специалисты часто сталкиваются с ситуацией, когда стандартный метод Вопрос() ведет себя непредсказуемо: форма «замирает», интерфейс перестает откликаться на действия пользователя в течение минуты, а программное обновление данных в табличной части не происходит. Особенно остро эта проблема проявляется при работе через удаленный рабочий стол (RDP) или в режиме RemoteApp. Разберем детально причины этих явлений и выясним, как правильно организовать диалог с пользователем в современных управляемых формах.

Причина 1: Блокировка потока и модальность

Проанализируем поведение метода Вопрос(). Этот метод является модальным. Это означает, что в момент его вызова выполнение программного кода полностью останавливается, и система ожидает ответа пользователя. В управляемом приложении, особенно в тонком клиенте, такое поведение считается устаревшим и нежелательным. Рассмотрим, почему это происходит:

  1. Замер производительности: Когда вы видите в замере производительности длительность выполнения метода в 40-60 секунд, это не означает, что код «тормозит». Это время, которое система потратила на ожидание, пока пользователь нажмет кнопку в диалоговом окне.
  2. Режим использования модальности: Если в свойствах вашей конфигурации установлено значение РежимИспользованияМодальности = НеИспользовать, метод Вопрос() попросту вызовет исключение. Однако даже если модальность включена, современные браузеры и средства публикации могут блокировать такие окна.

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

Решение: Переход на асинхронные вызовы

Рассмотрим по шагам, как переписать обработчик события ПриИзменении, чтобы избежать зависаний. Основная идея заключается в том, что мы не «ждем» ответа в текущей процедуре, а передаем управление специальной процедуре-оповещению.

Разберем пример правильной реализации:


&НаКлиенте
Процедура ЗаявкиНаТранспортСтатусПриИзменении(Элемент)
    
    ТекущиеДанные = Элементы.ЗаявкиНаТранспорт.ТекущиеДанные;
    
    // Если статус снят, дополнительные вопросы не задаем
    Если Не ТекущиеДанные.Статус Тогда 
        Возврат; 
    КонецЕсли;

    // Подготавливаем описание оповещения (куда вернуться после ответа пользователя)
    Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияВопросаЗаявки", ЭтотОбъект);
    
    // Вызываем неблокирующее окно
    ТекстВопроса = "Выполнить обработку заявки?";
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
    // ВАЖНО: Весь код, который должен выполниться ПОСЛЕ ответа, 
    // НЕЛЬЗЯ писать ниже этой строки. Процедура завершится сразу.
КонецПроцедуры

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

Причина 2: Особенности отрисовки в RemoteApp

Выясним причину странного поведения, когда форма «отлипает» только после сворачивания-разворачивания окна. Это классическая проблема графической подсистемы при работе через RemoteApp. Когда 1С вызывает модальное окно (особенно устаревшим методом Вопрос()), оно может не получить фокус или отрисоваться «за» основным окном.

Проанализируем ситуацию: основное окно заблокировано, так как ждет ответа, а окно вопроса не видно пользователю. В результате создается полное ощущение зависания. Использование асинхронного метода ПоказатьВопрос() частично решает эту проблему, так как окно создается иными механизмами платформы. Однако если проблема сохраняется, системным администраторам рекомендуется:

  1. Отключить аппаратное ускорение графики в настройках 1С (параметр DisableHardwareAcceleration=1 в 1CEStart.cfg).
  2. Использовать полноценный RDP-сеанс вместо публикации отдельных приложений через RemoteApp.

Причина 3: Ошибка обновления данных методом Прочитать()

Посмотрим на попытку автора обновить форму через ЭтаФорма.Прочитать(). В 1С метод Прочитать() предназначен для того, чтобы перечитать данные объекта из базы данных в память формы. Если вы программно изменили данные в табличной части, но еще не записали документ, вызов Прочитать() просто **удалит** ваши изменения, заменив их теми, что сохранены в базе.

Для корректного обновления интерфейса мы рекомендуем следовать следующим правилам:

Итоги и рекомендации

Подводя итог, можно сказать, что «зависания» в 1С чаще всего связаны с попыткой использовать синхронные (модальные) методы там, где архитектура управляемого приложения требует асинхронности.

Проанализируем ключевые моменты:

  1. Никогда не используйте Вопрос() в управляемых формах. Всегда используйте ПоказатьВопрос() с ОписаниеОповещения.
  2. Помните, что код внутри ПриИзменении после вызова ПоказатьВопрос() продолжит выполняться, не дожидаясь ответа пользователя. Логику нужно переносить в процедуру обратного вызова (Callback).
  3. Если ваша информационная система работает через RemoteApp, минимизируйте использование всплывающих окон или обеспечьте корректную настройку терминальных серверов.
  4. Для визуального обновления формы используйте ОбновитьОтображениеДанных(), а не Прочитать(), чтобы не потерять введенные пользователем данные.

Соблюдение этих принципов позволит создавать отзывчивые интерфейсы, которые будут стабильно работать в любых условиях эксплуатации.

← На главную