Как предотвратить потерю фокуса и закрытие списков автоподбора при фоновом вызове сервера?

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

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

Анализируем причину проблемы

Выясним причину такого поведения системы. До версии 8.3.12 механизмы синхронизации данных между клиентом и сервером работали менее агрессивно. В новых версиях платформы любой вызов сервера (даже &НаСервереБезКонтекста) заставляет платформу выполнять проверку состояния управляемой формы. Если система фиксирует, что данные на форме или её структура могут потенциально измениться, она инициирует обновление интерфейса.

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

Решение 1: Проверка активности пользователя через ТекстРедактирования

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

Для этого мы будем использовать свойство ТекстРедактирования. Разберем по шагам, как это реализовать:

  1. Определим текущий активный элемент формы.
  2. Проверим, является ли он полем ввода.
  3. Сравним текущее значение реквизита с текстом, который фактически набран в поле.

Посмотрим на пример кода, который реализует эту логику:


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

Решение 2: Динамическое управление обработчиком ожидания

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

Разберем алгоритм реализации:

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

Решение 3: Оптимизация серверных вызовов

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

Проанализируем рекомендации:

  1. Используйте только &НаСервереБезКонтекста для фоновых задач. Это минимизирует объем передаваемых данных и нагрузку на синхронизацию формы.
  2. Никогда не вызывайте ОбновитьОтображениеДанных() в циклическом обработчике, если в этом нет острой необходимости.
  3. Если вам нужно обновить только конкретное значение, попробуйте изменить только этот реквизит, не затрагивая всю форму.

Решение 4: Использование фоновых заданий для длительных операций

Если серверная функция выполняется долго (более 1 секунды), пользователь увидит зависание интерфейса. В таких случаях рассмотрим схему с использованием фоновых заданий:

  1. Клиентский обработчик запускает фоновое задание на сервере.
  2. При следующем срабатывании (через 3 секунды) обработчик проверяет состояние задания через ФоновыеЗадания.НайтиПоУникальномуИдентификатору.
  3. Если задание завершено, клиент забирает результат.

Это позволяет разнести во времени момент «тяжелого» вычисления и момент обновления интерфейса. Посмотрим на структуру такого решения:


&НаКлиенте
Процедура ОбработчикОжидания()
    // Проверяем, не занят ли пользователь (как в Решении 1)
    Если ПользовательВводитТекст() Тогда
        Возврат;
    КонецЕсли;

    Если ИдентификаторЗадания = Неопределено Тогда
        ИдентификаторЗадания = ЗапуститьЗаданиеНаСервере();
    Иначе
        Состояние = ПроверитьСостояниеЗадания(ИдентификаторЗадания);
        Если Состояние = "Завершено" Тогда
            Результат = ПолучитьРезультат(ИдентификаторЗадания);
            // Обновляем реквизиты формы
            СуммаОплаты = Результат;
            ИдентификаторЗадания = Неопределено;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

← На главную