Почему при вводе текста в окне поиска динамического списка удаляются символы и пропадает фокус

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

Многие разработчики и пользователи 1С:Предприятие 8.3 (особенно на релизах платформы 8.3.23, 8.3.24 и выше) сталкиваются с крайне неприятной ситуацией. При попытке быстро набрать текст в строке поиска динамического списка (например, в справочнике «Номенклатура» или «Контрагенты»), курсор внезапно «прыгает», текст стирается, а ввод начинается заново. Создается впечатление, что программа «не успевает» за пользователем и сбрасывает его действия.

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

Выясним причину: механизм асинхронного поиска и конфликт событий

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

Проблема возникает в тот момент, когда в динамическом списке определен обработчик события ПриАктивизацииСтроки. Рассмотрим цепочку событий, которая приводит к ошибке:

  1. Пользователь вводит первый символ в строку поиска.
  2. Платформа инициирует поиск и обновляет содержимое таблицы (динамического списка).
  3. При обновлении данных в списке автоматически активизируется первая строка (или сохраняется выбор на текущей).
  4. Срабатывает событие ПриАктивизацииСтроки.
  5. Если в этом событии выполняется код, который хотя бы минимально изменяет состояние формы (например, меняет видимость кнопок, обновляет текст надписей с остатками или ценами, делает контекстный серверный вызов), платформа инициирует полную перерисовку формы.
  6. Во время перерисовки фокус ввода «слетает» с элемента СписокСтрокаПоиска и возвращается на саму таблицу. В результате ввод прерывается, а следующий символ может либо не напечататься, либо стереть предыдущее значение из-за особенностей фокуса.

Способ 1. Проверка активного элемента формы (быстрое решение)

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

Рассмотрим пример кода, который необходимо добавить в самое начало обработчика ПриАктивизацииСтроки на клиенте:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    
    // Проверяем, не находится ли фокус в строке поиска
    Если ЭтаФорма.ТекущийЭлемент.Имя = "СписокСтрокаПоиска" Тогда
        Возврат;
    КонецЕсли;

    // Далее идет основной код обработки активизации строки
    ОбновитьДополнительныеДанныеНаФорме();
    
КонецПроцедуры

Разберем этот пример. Системное имя элемента строки поиска в управляемых формах обычно соответствует шаблону ИмяСпискаСтрокаПоиска. Проверяя свойство ТекущийЭлемент, мы блокируем выполнение кода, вызывающего перерисовку, пока пользователь взаимодействует с поисковым полем. Это позволяет платформе спокойно завершить асинхронные процессы фильтрации без прерывания ввода.

Способ 2. Использование обработчика ожидания (рекомендуемый подход)

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

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


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    
    // Отключаем предыдущий вызов, если пользователь быстро перемещается по строкам
    ОтключитьОбработчикОжидания("ВыполнитьОбновлениеДанных");
    
    // Запускаем небольшую задержку (например, 0.2 секунды)
    // Это позволит строке поиска «проскочить» момент обновления без потери фокуса
    ПодключитьОбработчикОжидания("ВыполнитьОбновлениеДанных", 0.2, Истина);
    
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьОбновлениеДанных()
    // Здесь выполняем все серверные вызовы и обновление интерфейса
    ОбновитьПоказателиОбъектаСервер();
КонецПроцедуры

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

Способ 3. Оптимизация серверных вызовов

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

Для решения проблемы с поиском рекомендуется:

Посмотрим на пример оптимизированного вызова:


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

&НаСервереБезКонтекста
Функция ПолучитьДанныеСерверБезКонтекста(ВыбраннаяСсылка)
    // Логика получения остатков или цен
    Возврат "Остаток на складе: " + Справочники.Номенклатура.ПолучитьОстаток(ВыбраннаяСсылка);
КонецФункции

Особенности платформы 8.3.24 и баги Конфигуратора

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

Однако для пользовательских форм в 99% случаев виноват именно избыточный код в ПриАктивизацииСтроки. Если вы используете типовые решения (например, продукты фирмы «Рарус» или сложные конфигурации от 1С), проверьте, не добавлены ли там расширения, которые вносят свои изменения в логику активации строки.

Резюме

Для устранения проблемы «прыгающего» поиска выполним следующие шаги:

  1. Проверим наличие кода в событии ПриАктивизацииСтроки.
  2. Добавим условие Если ЭтаФорма.ТекущийЭлемент.Имя = "СписокСтрокаПоиска" Тогда Возврат; для мгновенного исправления.
  3. Для качественного решения переведем обновление данных на обработчик ожидания с задержкой 0.1–0.3 секунды.
  4. Максимально используем неконтекстные серверные вызовы для получения вспомогательной информации.

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

← На главную