Почему при переходе по строкам одной таблицы вызывается событие ПриАктивизацииСтроки у другой таблицы?

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

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

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

Главная причина кроется в механизме синхронизации клиентского контекста формы с сервером. В синтакс-помощнике платформы «1С:Предприятие» для события ПриАктивизацииСтроки элемента управления ТаблицаФормы зафиксировано четкое ограничение: внутри этого события крайне не рекомендуется выполнять вызовы серверных контекстных методов (с директивой &НаСервере).

Проанализируем цепочку событий, которая приводит к ложному срабатыванию:

  1. Пользователь активизирует строку в первой таблице формы.
  2. Срабатывает клиентский обработчик события, из которого вызывается серверная процедура &НаСервере для чтения данных или пересчета.
  3. Контекстный серверный вызов отправляет все состояние формы на сервер и возвращает его обратно на клиент.
  4. При возврате контекста клиентская платформа заново отрисовывает элементы управления. При обновлении состояния второй таблицы платформа восстанавливает или устанавливает позицию текущей строки по умолчанию.
  5. Позиционирование указателя расценивается платформой как новая активизация строки, что вызывает обработчик ПриАктивизацииСтроки уже во второй таблице. Это может породить лавинообразные каскадные вызовы и даже зацикливание формы.

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

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

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

Посмотрим на пример реализации:


&НаКлиенте
Процедура ТЧ1ПриАктивизацииСтроки(Элемент)
    ПодключитьОбработчикОжидания("ВыполнитьОбработкуСтрокиТЧ1", 0.1, Истина);
КонецПроцедуры

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

Способ 2. Проверка фокуса ввода текущего элемента

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

Посмотрим на пример кода:


&НаКлиенте
Процедура ТЧ2ПриАктивизацииСтроки(Элемент)
    Если ЭтаФорма.ТекущийЭлемент <> Элементы.ТЧ2 Тогда
        Возврат;
    КонецЕсли;

    // Основная логика обработки строки
КонецПроцедуры

Способ 3. Запоминание идентификатора текущей строки

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

Разберем реализацию логики:


&НаКлиенте
Перем ТекущийИдентификаторСтрокиТЧ1;

&НаКлиенте
Процедура ТЧ1ПриАктивизацииСтроки(Элемент)
    СтрокаТаблицы = Элемент.ТекущиеДанные;
    Если СтрокаТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Если ТекущийИдентификаторСтрокиТЧ1 = СтрокаТаблицы.ПолучитьИдентификатор() Тогда
        Возврат;
    КонецЕсли;

    ТекущийИдентификаторСтрокиТЧ1 = СтрокаТаблицы.ПолучитьИдентификатор();
    
    // Выполнение целевых действий
КонецПроцедуры

Способ 4. Использование процедур без контекста (&НаСервереБезКонтекста)

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

Посмотрим, как выглядит вызов без контекста:


&НаКлиенте
Процедура ТЧ1ПриАктивизацииСтроки(Элемент)
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        ДополнительнаяИнформация = ПолучитьИнформациюПоНоменклатуре(ТекущаяСтрока.Номенклатура);
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьИнформациюПоНоменклатуре(Знач СсылкаНоменклатура)
    // Чтение данных без передачи контекста формы
    Возврат СсылкаНоменклатура.Артикул;
КонецФункции

Способ 5. Использование флага взаимной блокировки событий

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


&НаКлиенте
Перем БлокировкаОбработки;

&НаКлиенте
Процедура ТЧ1ПриАктивизацииСтроки(Элемент)
    Если БлокировкаОбработки = Истина Тогда
        Возврат;
    КонецЕсли;

    БлокировкаОбработки = Истина;
    
    // Программное изменение строк или состава второй таблицы
    ОбновитьПодчиненнуюТаблицу();
    
    БлокировкаОбработки = Ложь;
КонецПроцедуры

&НаКлиенте
Процедура ТЧ2ПриАктивизацииСтроки(Элемент)
    Если БлокировкаОбработки = Истина Тогда
        Возврат;
    КонецЕсли;

    // Логика второй таблицы
КонецПроцедуры

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

← На главную