При разработке на управляемых формах 1С программисты часто сталкиваются с неприятным поведением метода ПодключитьОбработчикОжидания. Несмотря на то, что в официальной документации заявлено срабатывание только в "состоянии покоя", на практике система может посчитать покоем даже секундную паузу, пока пользователь обдумывает текст. В результате срабатывания фокус может "слететь" с поля, или набранный текст выделится целиком, что приведет к его удалению при нажатии следующей клавиши.
В этой статье мы подробно разберем, как определить, что пользователь занят вводом данных, и как правильно настроить логику формы, чтобы обработчик ожидания не мешал работе. Мы проанализируем несколько подходов — от простых проверок до продвинутых методов с использованием флагов и событий.
Самый простой и быстрый способ понять, где сейчас находится пользователь — это проверить свойство формы ТекущийЭлемент. Если фокус находится в поле ввода, мы можем предположить, что процесс редактирования запущен, и выполнение тяжелых процедур в обработчике ожидания следует отложить.
Рассмотрим пример кода, который можно вставить в начало вашей процедуры-обработчика:
&AtClient
Procedure ИмяВашегоОбработчикаОжидания()
// Проверяем, какой элемент сейчас активен
АктивныйЭлемент = ЭтаФорма.ТекущийЭлемент;
// Если это поле ввода, велика вероятность, что пользователь что-то печатает
Если ТипЗнч(АктивныйЭлемент) = Тип("ПолеФормы") Тогда
Если АктивныйЭлемент.Вид = ВидПоляФормы.ПолеВвода Тогда
// Пропускаем выполнение, если не хотим прерывать ввод
Возврат;
EndIf;
EndIf;
// Основная логика обработчика
// ...
EndProcedure
Проанализируем этот подход: он эффективен, если нам нужно просто "замереть", пока фокус стоит в любом текстовом поле. Однако стоит помнить, что пользователь может просто оставить курсор в поле и уйти пить кофе — в этом случае обработчик перестанет работать совсем. Поэтому этот метод лучше комбинировать с другими.
Более точный способ — отслеживать реальное нажатие клавиш. В 1С Управляемых формах нет глобального события нажатия клавиши, но мы можем использовать событие АвтоПодбор, которое срабатывает при каждом изменении текста пользователем.
Разберем алгоритм реализации по шагам:
Булево) с именем ПользовательРедактируетДанные.АвтоПодбор для критически важных полей будем устанавливать этот флаг в значение Истина.ПриИзменении или ОкончаниеВводаТекста будем сбрасывать флаг в Ложь.Посмотрим на пример реализации:
&AtClient
Var ПользовательРедактируетДанные; // Переменная модуля
&AtClient
Procedure ПриОткрытии(Отказ)
ПользовательРедактируетДанные = Ложь;
EndProcedure
&AtClient
Procedure ПолеВводаАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, Ожидание, СтандартнаяОбработка)
ПользовательРедактируетДанные = Истина;
// Можно также запустить таймер сброса этого флага через 5 секунд простоя
EndProcedure
&AtClient
Procedure ПолеВводаПриИзменении(Элемент)
ПользовательРедактируетДанные = Ложь;
EndProcedure
В самом обработчике ожидания теперь достаточно проверять значение этой переменной. Это гарантирует, что пока идет активный набор, код 1С не будет перехватывать управление.
Если ваша проблема связана с тем, что обработчик ожидания обновляет динамический список или таблицу, из-за чего закрывается режим редактирования строки, используйте специализированные события таблиц. Выясним, как это работает на примере ПередНачаломИзменения.
Для табличной части или таблицы формы мы можем использовать следующие обработчики:
Этот метод считается наиболее надежным для предотвращения потери данных в многострочных частях документов, так как 1С четко фиксирует начало и конец транзакции редактирования строки.
Зачастую разработчики используют ПодключитьОбработчикОжидания для обновления данных, которые могли измениться в другой форме. Рассмотрим ситуацию: зачем нам таймер, который "дергает" сервер каждые 5 секунд, если можно использовать механизм Оповестить?
Вместо постоянного опроса системы, попробуем внедрить событийную модель:
Оповестить("ДанныеИзменены", ПараметрыОбновления);.ОбработкаОповещения.Преимущество этого метода в том, что нагрузка на систему снижается, а вероятность конфликта с вводом пользователя сводится к минимуму, так как обновление происходит только по факту реального изменения, а не по "слепому" расписанию.
Проанализируем экзотический, но крайне эффективный метод для веб-клиента или сложных интерфейсов. Если нам нужно отслеживать активность пользователя абсолютно во всей форме (движение мыши, нажатия любых клавиш), мы можем поместить на форму невидимое ПолеHTMLДокумента.
С помощью небольшого JavaScript-кода внутри HTML-контейнера можно перехватывать события onkeydown или onmousemove и передавать информацию обратно в 1С через изменение location.href или специальные методы взаимодействия с контейнером. Это позволит реализовать полноценный детектор "Idle Time" (времени простоя), как в профессиональных операционных системах, и запускать ваши обработчики только тогда, когда пользователь действительно отошел от компьютера.
Выяснив причины, по которым ПодключитьОбработчикОжидания может мешать пользователю, мы рекомендуем придерживаться следующей стратегии:
ЭтаФорма.ТекущийЭлемент в первой строке обработчика.ЭтаФорма.Модифицированность. Если форма изменена, возможно, стоит отложить автоматическое обновление.АвтоПодбор, если работа идет с текстовыми полями, где важен каждый символ.Применяя эти методы в комплексе, мы создадим отзывчивый и стабильный интерфейс, который будет помогать пользователю, а не мешать ему выполнять повседневные задачи.