При разработке интерактивных элементов в среде «1С:Предприятие 8.3» (таких как внутренние чаты, системы живых оповещений или панели мониторинга) разработчики часто сталкиваются с неприятным поведением интерфейса. Раз в несколько секунд у пользователя, который в этот момент заполняет документ или ищет элемент в справочнике, сбрасывается фокус ввода, закрываются открытые выпадающие списки (например, список автоподбора номенклатуры) или сбрасывается выделение текста. Это происходит в момент срабатывания обработчика ожидания, который обновляет данные на форме.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем внутренние механизмы платформы 1С, приводящие к сбросу фокуса, и рассмотрим практические способы её решения.
---
Для начала выясним причину такого поведения платформы. В управляемом приложении «1С:Предприятие» за отображение интерфейса отвечает клиентская часть, которая постоянно синхронизирует свое состояние с сервером. Когда мы используем метод ПодключитьОбработчикОжидания(), платформа по таймеру запускает экспортную процедуру клиентского модуля формы.
Если в этой процедуре происходит стандартное обновление данных, сценарий обычно выглядит следующим образом:
&НаСервере) для получения актуального состояния (например, запроса новых сообщений в регистре сведений).Особенно остро эта проблема проявлялась в версиях платформы 1С:Предприятие 8.3.12 (включая сборку 8.3.12.1685), где поведение фокуса при фоновых обновлениях содержало платформенные ошибки. В более поздних релизах платформы механизм удержания фокуса был существенно доработан, однако сама архитектурная особенность обновления контекста осталась прежней.
---
Самый эффективный способ борьбы со сбросом фокуса — это минимизация обращений к контексту формы. Нам незачем дергать сервер с контекстом всей формы каждые 10 секунд, если в 99% случаев никаких новых сообщений для пользователя не появилось.
Рассмотрим правильный алгоритм оптимизации:
&НаСервереБезКонтекста.Ложь. На клиенте мы сразу же завершаем работу обработчика, никак не изменяя реквизиты формы. Поскольку реквизиты не меняются и контекстного вызова не было, платформа не станет перерисовывать интерфейс, и фокус пользователя останется на месте.Истина, и только в этом случае мы вызываем контекстный метод для обновления списка сообщений.Посмотрим на пример реализации данного механизма в коде управляемой формы чата:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем обработчик ожидания на 10 секунд
ПодключитьОбработчикОжидания("ПроверитьОбновленияЧата", 10, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОбновленияЧата()
// Параметр ПоследняяДатаСообщения хранится в реквизитах формы на клиенте
ЕстьНовыеСообщения = ПроверитьНовыеСообщенияНаСервере(ПоследняяДатаСообщения, ТекущийПользовательЧат);
Если ЕстьНовыеСообщения Тогда
// Только при наличии реальных изменений обновляем данные формы
ОбновитьДанныеФормыКонтекстно();
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПроверитьНовыеСообщенияНаСервере(Знач ДатаПоследнего, Знач ПользовательПолучатель)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Чат.Период КАК Период
|ИЗ
| РегистрСведений.ЧатМеждуПользователями КАК Чат
|ГДЕ
| Чат.Период > &ДатаПоследнего
| И Чат.Получатель = &ПользовательПолучатель";
Запрос.УстановитьПараметр("ДатаПоследнего", ДатаПоследнего);
Запрос.УстановитьПараметр("ПользовательПолучатель", ПользовательПолучатель);
Выборка = Запрос.Выполнить().Выбрать();
Возврат Выборка.Следующий(); // Возвращает Истина, если найдена хотя бы одна новая запись
КонецФункции
&НаСервере
Процедура ОбновитьДанныеФормыКонтекстно()
// Здесь мы уже можем безопасно обновить динамический список или таблицу значений на форме.
// Сброс фокуса произойдет только в тот редкий момент, когда пользователю действительно придет сообщение.
Элементы.СписокСообщений.Обновить();
// Обновляем дату последнего сообщения на сервере, чтобы при следующем цикле не заходить сюда без надобности
ПоследняяДатаСообщения = ПолучитьМаксимальнуюДатуСообщений(ТекущийПользовательЧат);
КонецПроцедуры
---
Что делать, если пользователь прямо сейчас набирает длинное сообщение в поле ввода или выбирает контрагента, и даже редкий сброс фокуса (в момент прихода сообщения) для него критичен? Мы можем программно определять, занят ли пользователь вводом текста в данный момент.
Для этого проанализируем свойства элементов формы. У полей ввода есть свойство ТекстРедактирования. Если пользователь активно пишет в поле ввода чата или осуществляет поиск, это свойство заполнено и отличается от текущего сохраненного значения реквизита.
Рассмотрим пример кода, предотвращающий обновление формы во время активного редактирования:
&НаКлиенте
Процедура ПроверитьОбновленияЧатаСЗащитойФокуса()
// Проверим, не редактирует ли пользователь поле ввода прямо сейчас
ТекущийЭлементФормы = ЭтаФорма.ТекущийЭлемент;
Если ТипЗнч(ТекущийЭлементФормы) = Тип("ПолеФормы") Тогда
// Если фокус находится в поле ввода сообщения, и там идет активный ввод текста
Если ТекущийЭлементФормы.Имя = "ПолеВводаСообщения" И Не ПустаяСтрока(Элементы.ПолеВводаСообщения.ТекстРедактирования) Тогда
// Откладываем обновление интерфейса, чтобы не мешать пользователю писать текст
Возврат;
КонецЕсли;
КонецЕсли;
// Если пользователь не занят вводом, проверяем наличие сообщений
ЕстьНовыеСообщения = ПроверитьНовыеСообщенияНаСервере(ПоследняяДатаСообщения, ТекущийПользовательЧат);
Если ЕстьНовыеСообщения Тогда
ОбновитьДанныеФормыКонтекстно();
КонецЕсли;
КонецПроцедуры
---
Если вы используете старые релизы платформы 1С (особенно ветку 8.3.12 или ранние сборки 8.3.15), настоятельно рекомендуется обновиться на актуальные стабильные версии (например, современные сборки 8.3.22, 8.3.23 и выше).
В новых версиях платформы разработчики фирмы «1С» провели масштабную работу над оптимизацией веб-клиента и тонкого клиента, устранив баги, при которых фокус ввода «отваливался» от активного элемента даже при фоновых неконтекстных вызовах сервера. Начиная с версии 8.3.14, стабильность удержания курсора в полях ввода при обновлении соседних элементов формы была значительно повышена.
---
Если вы хотите полностью уйти от использования таймеров (обработчиков ожидания), которые в любом случае создают паразитную нагрузку на базу данных (ведь даже легкий запрос каждые 10 секунд от 500 пользователей создаст заметный поток обращений к СУБД), идеальным решением будет переход на **Систему взаимодействия**.
Система взаимодействия — это встроенный в платформу 1С механизм для мгновенного обмена сообщениями, файлами и выполнения аудио/видеозвонков. Она работает по принципу Push-технологий через протокол WebSockets.
Преимущества Системы взаимодействия:
Нюансы, о которых нужно знать:
Используя предложенные методики условного обновления через внеконтекстные вызовы &НаСервереБезКонтекста и защиту полей ввода от перерисовки во время набора текста, вы сможете создать максимально отзывчивый и комфортный чат для ваших пользователей прямо внутри базы 1С без раздражающих сбоев интерфейса.