При работе с управляемыми формами в 1С 8.3 часто возникает задача отображения актуального количества строк в динамическом списке. Особенно это актуально, когда пользователь применяет фильтры через "Расширенный поиск" или стандартную строку поиска. Проблема заключается в том, что динамический список (ДС) подгружает данные порциями, и простого свойства Количество(), как у таблицы значений, у него нет. В этой статье мы подробно разберем несколько способов, как «поймать» момент обновления списка и программно вычислить точное число строк, соответствующих установленным условиям. Для схожей задачи подсчета суммарных показателей по колонкам можно использовать метод настройки итогов в динамическом списке через вычисляемые поля.
Прежде чем переходить к сложному программированию, рассмотрим самый простой вариант, доступный в платформе, начиная с версии 8.3.10. Если нам нужно просто показать количество строк пользователю в подвале таблицы, мы можем воспользоваться встроенным функционалом. Выясним, как это сделать:
ОтображатьКоличество).При включении этой опции платформа сама будет выводить число записей в нижней части таблицы. Однако, если наша задача — вывести это число в заголовок вкладки или использовать в расчетах (как в ситуации автора темы), этот метод нам не подойдет, и нам придется использовать программные решения.
Это основной и наиболее правильный метод для отслеживания изменений в отборах и поиске. Проанализируем его преимущества: данное событие вызывается на сервере при любом изменении настроек компоновщика (отборы, сортировка, группировка, поиск), и оно обладает контекстом формы. Это значит, что мы можем напрямую обновлять реквизиты формы (например, наш счетчик) без лишних ухищрений.
Разберем пример реализации:
&НаСервере
Процедура СписокПриОбновленииПользовательскихНастроекНаСервере(Элемент, Настройки)
// Метод для пересчета количества
ОбновитьСчетчикСтрокНаСервере();
КонецПроцедуры
Внутри процедуры ОбновитьСчетчикСтрокНаСервере() мы будем выполнять программный запрос к базе данных, учитывая все текущие настройки динамического списка. О том, как написать такой запрос, мы поговорим в разделе про СКД.
Иногда стандартное обновление настроек не срабатывает (например, при специфическом поиске по строке). Тогда на помощь приходит событие самого динамического списка ПриПолученииДанныхНаСервере. Однако здесь есть сложность: процедура является &НаСервереБезКонтекста, и мы не можем напрямую изменить значение реквизита на форме.
Рассмотрим «хитрый» алгоритм с использованием временного хранилища и обработчика ожидания:
ПриСозданииНаСервере создаем уникальный адрес в хранилище и помещаем его в дополнительные свойства настроек списка.ПриПолученииДанныхНаСервере записываем в этот адрес сигнал (флаг) о том, что данные обновились.Пример программного кода для реализации этого механизма:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Резервируем адрес во временном хранилище
АдресВХранилище = ПоместитьВоВременноеХранилище(Ложь, УникальныйИдентификатор);
// Передаем адрес в настройки списка, чтобы он был доступен в безконтекстном методе
Список.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("АдресДляФлага", АдресВХранилище);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Проверяем наличие адреса и выставляем флаг обновления
Если Настройки.ДополнительныеСвойства.Свойство("АдресДляФлага") Тогда
ПоместитьВоВременноеХранилище(Истина, Настройки.ДополнительныеСвойства.АдресДляФлага);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем проверку флага раз в 1-2 секунды
ПодключитьОбработчикОжидания("ПроверитьОбновлениеСписка", 1, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОбновлениеСписка() Экспорт
Адрес = Список.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.АдресДляФлага;
Если ПолучитьИзВременногоХранилища(Адрес) = Истина Тогда
// Сбрасываем флаг и пересчитываем количество
ПоместитьВоВременноеХранилище(Ложь, Адрес);
ОбновитьКоличествоНаСервере();
КонецЕсли;
КонецПроцедуры
Теперь выясним, как именно получить число строк, учитывая все «хитрые» отборы пользователя. Самый надежный способ — использовать КомпоновщикНастроек динамического списка и механизм компоновки данных. Мы заставим систему сформировать текст запроса на основе текущих настроек, но вместо выбора всех полей попросим только КОЛИЧЕСТВО(*). Для лучшего понимания программной настройки схем компоновки пригодятся простые примеры работы с СКД.
Рассмотрим по шагам, как реализовать универсальную функцию подсчета:
&НаСервере
Функция ПолучитьКоличествоСтрокДинамическогоСписа(ИмяЭлементаСписка)
// 1. Получаем исполняемую схему и настройки
Схема = Элементы[ИмяЭлементаСписка].ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы[ИмяЭлементаСписка].ПолучитьИсполняемыеНастройки();
// 2. Подготавливаем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// 3. Извлекаем текст запроса из макета
ТекстЗапроса = МакетКомпоновки.НаборыДанных.НаборДанных1.Запрос;
// 4. Оборачиваем запрос для получения количества
ТекстЗапросаКоличество = "ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ (" + ТекстЗапроса + ") КАК ВложенныйЗапрос";
// 5. Выполняем запрос с параметрами из макета компоновки
Запрос = Новый Запрос(ТекстЗапросаКоличество);
Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
Запрос.УстановитьПараметр(Параметр.Имя, Параметр.Значение);
КонецЦикла;
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка[0];
КонецЕсли;
Возврат 0;
КонецФункции
Важное примечание: Использование метода ПолучитьИсполняемыеНастройки() крайне важно, так как именно он объединяет фиксированные отборы программиста, пользовательские настройки и данные из строки быстрого поиска (Ctrl+F). Если использовать просто Список.КомпоновщикНастроек.Настройки, данные поиска могут быть не учтены.
Проанализировав все способы, можно сделать следующие выводы для оптимизации работы приложения:
ПриОбновленииПользовательскихНастроекНаСервере — идеальный баланс.COUNT(*) может подвесить интерфейс. В таких случаях рассмотрите возможность выноса подсчета в фоновое задание.Выяснив причину того, почему стандартные методы иногда не видят изменения в поиске, и внедрив один из предложенных механизмов, вы сможете обеспечить пользователю актуальную информацию о количестве записей в любой момент работы с формой.