При разработке управляемых форм в 1С часто возникает задача динамического отображения сопутствующей информации (например, текущих остатков и цен номенклатуры) при перемещении пользователя по строкам таблицы или динамического списка. Разработчики традиционно используют для этого событие ПриАктивизацииСтроки. Однако при отладке выясняется, что данный обработчик вызывается неожиданно много раз: как при открытии формы, так и при обычном клике мышью на строку списка. Выясним причину такого поведения платформы и рассмотрим правильные варианты реализации данной задачи.
Проанализируем механику работы управляемой формы и динамического списка, которая приводит к серии вызовов обработчика:
ПриАктивизацииСтроки генерируется для каждого промежуточного элемента. Если на каждое срабатывание повесить прямой серверный вызов, интерфейс начинает подвисать из-за очереди запросов.Наиболее надежный и рекомендуемый способ обработки частых клиентских событий — это использование отложенного вызова с помощью методов ПодключитьОбработчикОжидания и ОтключитьОбработчикОжидания. Суть метода заключается в том, чтобы не отправлять запрос на сервер сразу, а подождать короткую паузу (обычно 0.1–0.3 секунды). Если за это время строка снова изменилась, таймер сбрасывается и запускается заново.
Разберем по шагам реализацию этого механизма в модуле управляемой формы:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
// Снимаем предыдущий отложенный вызов, если пользователь продолжает перемещаться
ОтключитьОбработчикОжидания("ОбновитьОстаткиПоВыбраннойНоменклатуре");
// Подключаем однократный вызов с минимальной задержкой
ПодключитьОбработчикОжидания("ОбновитьОстаткиПоВыбраннойНоменклатуре", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьОстаткиПоВыбраннойНоменклатуре()
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
ОстатокНаСкладе = 0;
Возврат;
КонецЕсли;
// Выполняем серверный вызов только после фиксации пользователя на строке
ОстатокНаСкладе = ПолучитьОстатокНоменклатурыНаСервере(ТекущиеДанные.Ссылка);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьОстатокНоменклатурыНаСервере(НоменклатураСсылка)
// Запрос к виртуальной таблице остатков регистра накопления
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Остаток;
КонецЕсли;
Возврат 0;
КонецФункции
В результате такого подхода при быстрой прокрутке списка сервер не нагружается промежуточными запросами, а расчет остатков выполняется ровно один раз — когда пользователь остановил курсор на требуемом товаре.
Рассмотрим ситуацию, когда форма повторно вызывает событие ПриАктивизацииСтроки для одной и той же номенклатуры (например, при клике мышью в разные колонки той же строки). В таком случае достаточно отсечь лишние вызовы простой проверкой через переменную модуля формы.
Посмотрим на пример реализации:
&НаКлиенте
Переменная ТекущаяОбработаннаяНоменклатура;
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Если строка фактически не изменилась, прерываем выполнение
Если ТекущаяОбработаннаяНоменклатура = ТекущиеДанные.Ссылка Тогда
Возврат;
КонецЕсли;
ТекущаяОбработаннаяНоменклатура = ТекущиеДанные.Ссылка;
// Переходим к получению остатков
ОтключитьОбработчикОжидания("ОбновитьОстаткиПоВыбраннойНоменклатуре");
ПодключитьОбработчикОжидания("ОбновитьОстаткиПоВыбраннойНоменклатуре", 0.1, Истина);
КонецПроцедуры
Проанализируем альтернативный архитектурный подход: вместо вызова сервера на каждую смену строки можно включить вывод остатков непосредственно в запрос динамического списка формы выбора.
Разберем особенности этого способа:
РегистрНакопления.ТоварыНаСкладах.Остатки).Список.Параметры.УстановитьЗначениеПараметра() при открытии формы или смене склада в шапке.ПриАктивизацииСтроки в таком сценарии вообще не используется, что полностью устраняет проблему лишних клиент-серверных вызовов и обеспечивает максимальную отзывчивость интерфейса.Резюме: Если требуется показывать остаток в отдельной информационной панели под списком, оптимальным решением является связка события ПриАктивизацииСтроки и однократного обработчика ожидания ПодключитьОбработчикОжидания. Если же остатки должны быть видны сразу по всем товарам в таблице, расчет целесообразно перенести прямо в текст запроса динамического списка.