Почему не срабатывает событие ПриАктивизацииСтроки при поиске в динамическом списке и как это исправить?

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

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

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

Проанализируем причину проблемы

Событие ПриАктивизацииСтроки генерируется платформой в тот момент, когда фокус перемещается с одной строки на другую. Ключевое слово здесь — перемещение. Рассмотрим внутреннюю механику работы стандартного поиска:

  1. Пользователь вводит текст в строку поиска.
  2. Платформа применяет фильтр к данным динамического списка на уровне СУБД или внутреннего кэша.
  3. Состав строк в списке меняется, лишние записи скрываются.
  4. Если строка, которая была активной до начала поиска, осталась в результатах, то с точки зрения платформы ТекущаяСтрока (идентификатор строки) не изменилась.

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

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

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

Рассмотрим пример реализации кода:


&НаКлиенте
Перем ПредыдущаяСтрока; // Глобальная переменная модуля формы

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ПодключитьОбработчикОжидания("ПроверитьОбновлениеАктивнойСтроки", 0.3);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОбновлениеАктивнойСтроки()
    ТекущаяСтрока = Элементы.Список.ТекущаяСтрока;
    
    // Проверяем, изменился ли идентификатор строки
    Если ТекущаяСтрока <> ПредыдущаяСтрока Тогда
        ПредыдущаяСтрока = ТекущаяСтрока;
        // Здесь вызываем процедуру, которая должна была сработать ПриАктивизацииСтроки
        ВыполнитьЛогикуПриСменеСтроки(ТекущаяСтрока);
    КонецЕсли;
КонецПроцедуры

Важный нюанс: использование интервала 0.3 секунды является оптимальным. Это достаточно быстро, чтобы пользователь не заметил задержки, и достаточно редко, чтобы не создавать избыточную нагрузку на клиентское приложение.

Способ 2. Создание собственного поля поиска

Для более чистого и контролируемого кода мы можем отказаться от стандартной строки поиска в пользу собственной. Это позволит нам точно знать, когда поиск начался и когда он закончился. Рассмотрим, как это реализовать.

  1. Добавим на форму реквизит СтрокаПоиска (тип Строка).
  2. Разместим его над динамическим списком.
  3. В событии ПриИзменении этого поля пропишем программную установку отбора.

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

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

Способ 3. Использование события ПриОбновленииСоставаДанных

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

Рассмотрим, как его использовать правильно, чтобы избежать зацикливания и падения производительности:

  1. Создадим обработчик события ПриОбновленииСоставаДанных для таблицы списка.
  2. Внутри обработчика проверим, изменилась ли ТекущаяСтрока.

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

Внимание: Будьте осторожны с этим событием. Оно срабатывает очень часто (при прокрутке, обновлении, поиске), поэтому внутри него нельзя размещать тяжелые серверные вызовы без предварительной проверки условий.

Выясним, какой метод лучше выбрать?

Подведем итог нашему исследованию:

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

← На главную