Почему не работает ВнешнееСобытие в модальном окне 1С и как это исправить?

Программист IT и автоматизация бизнеса
← На главную

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

Самое примечательное происходит после закрытия модальной формы: все отсканированные штрихкоды лавиной «сыплются» в обработчик родительской формы. В то же время, если открыть эту форму в обычном (немодальном) режиме, всё работает безупречно. В этой статье мы детально разберем технические причины такого поведения платформы 1С и рассмотрим несколько надежных способов обхода и решения этой проблемы.

В чем кроется техническая причина проблемы?

Для того чтобы понять, почему так происходит, нам необходимо проанализировать особенности взаимодействия платформы «1С:Предприятие» с операционной системой Windows и драйверами торгового оборудования. В основе работы механизма внешних событий лежит концепция состояния простоя (idle state) приложения.

Разберем этот процесс по шагам:

  1. Очередь сообщений операционной системы: Платформа 1С использует единую системную очередь сообщений. Когда пользователь не совершает активных действий, операционная система отправляет приложению сигнал о переходе в состояние простоя. Именно в этот момент ядро 1С начинает обрабатывать накопившиеся асинхронные вызовы, включая сигналы от внешних компонент (включая драйверы сканеров штрихкодов).
  2. Блокировка модальным окном: При вызове метода ОткрытьМодально() платформа создает изолированную локальную очередь сообщений для конкретного окна. Эта очередь перехватывает весь пользовательский ввод. К сожалению, системные сообщения о переходе в состояние простоя «застревают» в глобальной очереди Windows и не доходят до обработчиков ядра 1С. В результате события от сканера накапливаются в буфере, но не обрабатываются до тех пор, пока модальное окно не закроется и управление не вернется основной очереди приложения.
  3. Проверка доступности ввода: Внутренний маршрутизатор событий 1С распределяет внешние события только тем формам, для которых метод ВводДоступен() возвращает значение Истина. Когда открывается модальное окно, родительские формы блокируются, и ввод для них становится недоступен. Если драйвер оборудования остался жестко ассоциирован с родительской формой, событие уходит «в пустоту».

Ниже мы подробно разберем практические варианты решения этой проблемы, начиная от простых обходных путей в старых конфигурациях и заканчивая современными стандартами разработки на управляемых формах.

---

Способ 1. Использование обработчика ожидания (Быстрый обход)

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

Рассмотрим пример реализации этого подхода в коде родительской формы:


Процедура ВнешнееСобытие(Источник, Событие, Данные)
    
    // Сначала обрабатываем текущее событие сканирования
    ПолучитьСерверТО().ОбработатьВнешнееСобытие(Источник, Событие, Данные, ЭтаФорма);
    
    // Вместо мгновенного модального открытия подключаем обработчик ожидания
    // Интервал устанавливаем минимальный — например, 0.1 секунды
    ПодключитьОбработчикОжидания("ОткрытьМодальноеОкноПослеСканирования", 0.1, Истина);
    
КонецПроцедуры

Процедура ОткрытьМодальноеОкноПослеСканирования()
    
    // Данный метод вызывается уже после полной очистки очереди текущего события
    ПараметрыФормы = Новый Структура;
    ОткрытьФормуМодально("ОбщаяФорма.ФормаВводаДанныхСШК", ПараметрыФормы);
    
КонецПроцедуры

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

---

Способ 2. Управление подключением торгового оборудования принудительно

Зачастую внешние события не доходят до модальной формы потому, что сканер штрихкодов остается монопольно захваченным другой формой приложения. Выясним причину: если в фоне открыто несколько окон, которые также используют торговое оборудование, 1С может блокировать передачу событий на уровне внутренней библиотеки. Чтобы решить эту проблему, необходимо реализовать строгое правило: активным к оборудованию в каждый момент времени должно быть только одно окно.

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

Код в родительской форме:


Процедура ВыполнитьОткрытиеМодальногоОкна()
    
    // Принудительно отключаем обработку оборудования на текущей форме
    ПоддерживаемыеОборудованиемКлиент.ОтключитьУстройствоДляФормы(ЭтаФорма);
    
    // Открываем форму в модальном режиме
    ОткрытьФормуМодально("ОбщаяФорма.ФормаВводаДанныхСШК");
    
    // После закрытия модального окна восстанавливаем подключение к сканеру
    ПоддерживаемыеОборудованиемКлиент.ПодключитьУстройствоДляФормы(ЭтаФорма);
    
КонецПроцедуры

Код в открываемой модальной форме:


Процедура ПриОткрытии()
    
    // Модальная форма принудительно захватывает управление сканером
    ПоддерживаемыеОборудованиемКлиент.ПодключитьУстройствоДляФормы(ЭтаФорма);
    
КонецПроцедуры

Процедура ПриЗакрытии()
    
    // Освобождаем устройство перед закрытием окна
    ПоддерживаемыеОборудованиемКлиент.ОтключитьУстройствоДляФормы(ЭтаФорма);
    
КонецПроцедуры

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

---

Способ 3. Переход на блокировку окна владельца (Современный стандарт 1С 8.3)

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

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

Проанализируем пример перевода кода на асинхронный лад:


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

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

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

← На главную