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