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