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