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