В разработке на платформе 1С:Предприятие 8.3 динамический список является одним из самых часто используемых элементов интерфейса. Однако разработчики часто сталкиваются с существенным ограничением: у динамического списка отсутствует стандартное клиентское событие "ПриОбновлении" или "ПослеПоиска". Это создает сложности, когда необходимо вывести итоги (например, общую сумму документов), которые должны актуализироваться каждый раз, когда пользователь меняет отборы, использует поиск или просто обновляет список кнопкой "Еще — Обновить".
В этой статье мы подробно разберем, как обойти это ограничение, какие методы платформы использовать для расчета итогов и как правильно оптимизировать этот процесс, чтобы не перегружать сервер.
Для начала проанализируем ситуацию с точки зрения архитектуры платформы. Динамический список оправдывает свое название: он считывает данные порциями (динамически) по мере прокрутки пользователем. Сервер базы данных не возвращает все 100 000 записей сразу, он отдает только те, что видны на экране. Именно поэтому расчет итогов по "видимым" данным будет методологически неверным — нам нужно знать сумму по всем записям, которые соответствуют текущим фильтрам пользователя, а не только по тем, что загружены в клиентскую часть. Отсутствие единого события связано с тем, что список может обновляться крайне часто (при каждом движении скролла или вводе символа в строку поиска), и автоматический пересчет тяжелых итогов привел бы к потере производительности.
Это самый популярный и надежный метод. Суть заключается в том, что мы не пытаемся поймать само событие обновления, а периодически или по триггеру проверяем состояние списка. Рассмотрим пример, когда расчет запускается через небольшую паузу после изменения отборов. Это позволяет избежать многократных вызовов, если пользователь быстро вводит текст в строку поиска.
Разберем реализацию с использованием метода ПодключитьОбработчикОжидания:
&НаКлиенте
Процедура ПриИзмененииОтбора(Элемент)
// Вместо мгновенного расчета подключаем обработчик с задержкой 0.5-1 секунда
ПодключитьОбработчикОжидания("Подключаемый_ОбновитьИтоги", 0.7, Истина);
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_ОбновитьИтоги()
ОбновитьИтогиНаСервере();
КонецПроцедуры
Начиная с версии платформы 8.3.6, у разработчиков появилась возможность программно получить схему и настройки, которые динамический список использует в данный момент. Это "золотой стандарт" для расчета итогов, так как он учитывает все пользовательские отборы, группировки и даже встроенный поиск.
Рассмотрим по шагам, как получить итог на сервере:
&НаСервере
Функция ОбновитьИтогиНаСервере()
// 1. Получаем схему и настройки динамического списка
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
// 2. Подготавливаем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , ,
Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// 3. Выполняем запрос
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТаблицаРезультата = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// 4. Получаем итог по нужной колонке
СуммаИтог = ТаблицаРезультата.Итог("СуммаДокумента");
Возврат СуммаИтог;
КонецФункции
Предыдущий пример имеет один недостаток: если в списке 50 000 строк, система попытается выгрузить их все в ТаблицаЗначений на сервере, чтобы просто посчитать сумму. Это неэффективно. Проанализируем, как можно ускорить процесс, заставив СУБД выполнить агрегатный запрос SUM().
Для этого перед выполнением компоновки мы можем программно изменить схему, удалив из неё все выбранные поля и добавив только одно поле-итог. Выясним, как это реализовать:
// Внутри серверной функции перед выполнением компоновщика макета:
Схема.ВыбранныеПоля.Очистить();
НовоеПоле = Схема.ВыбранныеПоля.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
НовоеПоле.Поле = Новый ПолеКомпоновкиДанных("СуммаДокумента");
// В настройках также оставляем только агрегатную функцию, если это возможно в вашей версии
Важный момент: использование ПолучитьИсполняемыеНастройкиКомпоновкиДанных гарантирует, что даже если пользователь воспользовался сложным поиском через Alt+F, эти условия попадут в ваш запрос и итог будет корректным.
Некоторые разработчики используют событие ПриПолученииДанныхНаСервере. Посмотрим на этот метод критически. Это событие срабатывает при каждой отрисовке строк списка. Если мы будем выполнять тяжелый запрос итогов прямо здесь, интерфейс начнет "тормозить" при скроллинге.
Однако, этот метод можно использовать для установки флага необходимости обновления. Выясним логику: в событии СписокПриПолученииДанныхНаСервере мы понимаем, что данные изменились. Мы можем передать этот флаг на клиент, и уже на клиенте в обработчике ПриАктивизацииСтроки (который срабатывает реже) или через короткий обработчик ожидания выполнить расчет.
Для реализации качественного интерфейса с итогами в динамическом списке рекомендуется комбинированный подход:
ПолучитьИсполняемуюСхемуКомпоновкиДанных — это наиболее современный и точный способ в управляемом приложении.ТекущиеДанные списка содержат информацию только о выделенной строке, поэтому для суммирования всегда нужно обращаться к базе данных через запрос или СКД.Используя эти техники, вы сможете создать функциональные и быстрые списки, которые будут предоставлять пользователям актуальную аналитическую информацию в режиме реального времени.