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