Как предотвратить активацию неактивной формы при изменении элементов в ОбработкаОповещения?

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

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

Почему происходит смена активного окна

Проанализируем механизм работы платформы 1С при обработке оповещений. Метод Оповестить() рассылает событие синхронно по всем открытым окнам клиентского приложения. Когда в модуле неактивной формы выполняется код модификации элементов управления:


&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Элементы.ГруппаШапка.ТолькоПросмотр = Истина;
    Элементы.ФормаЗаполнитьПоНомеру.Доступность = Ложь;
КонецПроцедуры

Происходит следующее: при изменении доступности элементов, на которых ранее находился курсор или фокус ввода в неактивной форме, платформа инициирует внутренний перерасчет свойства ТекущийЭлемент. Клиентский движок интерфейса запускает цикл перерисовки и переводит фокус на изменившееся окно, делая его активным.

Рассмотрим основные и наиболее надежные способы предотвращения нежелательной активации формы.

Способ 1. Отложенное обновление интерфейса при помощи метода ВводДоступен

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

Пошагово реализуем этот алгоритм:

  1. В модуле неактивной формы объявляем переменную или реквизит формы для хранения признака необходимости обновления.
  2. В процедуре ОбработкаОповещения проверяем, активна ли форма в данный момент. Если форма неактивна, просто взводим флаг.
  3. В обработчике события формы ПриАктивизации (или при интерактивных действиях) выполняем фактическое обновление элементов, если флаг установлен.

Посмотрим на пример реализации:


&НаКлиенте
Перем мТребуетсяОбновитьИнтерфейс;

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

&НаКлиенте
Процедура ПриАктивизации()
    Если мТребуетсяОбновитьИнтерфейс = Истина Тогда
        ОбновитьДоступностьЭлементов();
        мТребуетсяОбновитьИнтерфейс = Ложь;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьДоступностьЭлементов()
    Элементы.ГруппаШапка.ТолькоПросмотр = Истина;
    Элементы.ФормаЗаполнитьПоНомеру.Доступность = Ложь;
КонецПроцедуры

Способ 2. Использование механизма Условного оформления

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

Рассмотрим, как это работает: в обработчике оповещения мы меняем только значения данных (реквизитов), а платформа берет на себя визуальное отображение (только просмотр, доступность, цвет) без принудительной активации окна.

Способ 3. Применение однократного обработчика ожидания

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

Посмотрим на код вызова:


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

&НаКлиенте
Процедура ПрименитьИзмененияИнтерфейса()
    Элементы.ГруппаШапка.ТолькоПросмотр = Истина;
    Элементы.ФормаЗаполнитьПоНомеру.Доступность = Ложь;
КонецПроцедуры

Способ 4. Возврат фокуса в исходную форму через контекст источника

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

Разберем пример передачи контекста:


// В исходной Форме 1:
Оповестить("СобытиеИзмененияДанных", Неопределено, ЭтотОбъект);

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

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

← На главную