Как решить проблему сброса фокуса ввода и закрытия списков выбора при работе обработчика ожидания в 1С

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

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

В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем внутренние механизмы платформы 1С, приводящие к сбросу фокуса, и рассмотрим практические способы её решения.

---

Почему обработчик ожидания ломает интерфейс пользователя?

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

Если в этой процедуре происходит стандартное обновление данных, сценарий обычно выглядит следующим образом:

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

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

---

Решение 1. Оптимизация обновления через внеконтекстные вызовы

Самый эффективный способ борьбы со сбросом фокуса — это минимизация обращений к контексту формы. Нам незачем дергать сервер с контекстом всей формы каждые 10 секунд, если в 99% случаев никаких новых сообщений для пользователя не появилось.

Рассмотрим правильный алгоритм оптимизации:

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

Посмотрим на пример реализации данного механизма в коде управляемой формы чата:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем обработчик ожидания на 10 секунд
    ПодключитьОбработчикОжидания("ПроверитьОбновленияЧата", 10, Ложь);
КонецПроцедуры

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

&НаСервереБезКонтекста
Функция ПроверитьНовыеСообщенияНаСервере(Знач ДатаПоследнего, Знач ПользовательПолучатель)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	Чат.Период КАК Период
        |ИЗ
        |	РегистрСведений.ЧатМеждуПользователями КАК Чат
        |ГДЕ
        |	Чат.Период > &ДатаПоследнего
        |	И Чат.Получатель = &ПользовательПолучатель";
        
    Запрос.УстановитьПараметр("ДатаПоследнего", ДатаПоследнего);
    Запрос.УстановитьПараметр("ПользовательПолучатель", ПользовательПолучатель);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Возврат Выборка.Следующий(); // Возвращает Истина, если найдена хотя бы одна новая запись
    
КонецФункции

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

---

Решение 2. Проверка активности ввода пользователя

Что делать, если пользователь прямо сейчас набирает длинное сообщение в поле ввода или выбирает контрагента, и даже редкий сброс фокуса (в момент прихода сообщения) для него критичен? Мы можем программно определять, занят ли пользователь вводом текста в данный момент.

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

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


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

---

Решение 3. Обновление платформы «1С:Предприятие»

Если вы используете старые релизы платформы 1С (особенно ветку 8.3.12 или ранние сборки 8.3.15), настоятельно рекомендуется обновиться на актуальные стабильные версии (например, современные сборки 8.3.22, 8.3.23 и выше).

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

---

Альтернативный подход: Система взаимодействия (штатный механизм 1С)

Если вы хотите полностью уйти от использования таймеров (обработчиков ожидания), которые в любом случае создают паразитную нагрузку на базу данных (ведь даже легкий запрос каждые 10 секунд от 500 пользователей создаст заметный поток обращений к СУБД), идеальным решением будет переход на **Систему взаимодействия**.

Система взаимодействия — это встроенный в платформу 1С механизм для мгновенного обмена сообщениями, файлами и выполнения аудио/видеозвонков. Она работает по принципу Push-технологий через протокол WebSockets.

Преимущества Системы взаимодействия:

Нюансы, о которых нужно знать:

Используя предложенные методики условного обновления через внеконтекстные вызовы &НаСервереБезКонтекста и защиту полей ввода от перерисовки во время набора текста, вы сможете создать максимально отзывчивый и комфортный чат для ваших пользователей прямо внутри базы 1С без раздражающих сбоев интерфейса.

← На главную