Как получить количество строк динамического списка после применения поиска или отбора в управляемых формах

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с управляемыми формами в 1С 8.3 часто возникает задача отображения актуального количества строк в динамическом списке. Особенно это актуально, когда пользователь применяет фильтры через "Расширенный поиск" или стандартную строку поиска. Проблема заключается в том, что динамический список (ДС) подгружает данные порциями, и простого свойства Количество(), как у таблицы значений, у него нет. В этой статье мы подробно разберем несколько способов, как «поймать» момент обновления списка и программно вычислить точное число строк, соответствующих установленным условиям. Для схожей задачи подсчета суммарных показателей по колонкам можно использовать метод настройки итогов в динамическом списке через вычисляемые поля.

Способ 1. Использование стандартного свойства «Отображать количество записей»

Прежде чем переходить к сложному программированию, рассмотрим самый простой вариант, доступный в платформе, начиная с версии 8.3.10. Если нам нужно просто показать количество строк пользователю в подвале таблицы, мы можем воспользоваться встроенным функционалом. Выясним, как это сделать:

  1. Откроем конфигуратор и выберем нужную форму.
  2. Найдем элемент формы типа Таблица, связанный с нашим динамическим списком.
  3. В свойствах таблицы найдем флажок Отображать количество записей (или программное свойство ОтображатьКоличество).

При включении этой опции платформа сама будет выводить число записей в нижней части таблицы. Однако, если наша задача — вывести это число в заголовок вкладки или использовать в расчетах (как в ситуации автора темы), этот метод нам не подойдет, и нам придется использовать программные решения.

Способ 2. Событие «ПриОбновленииПользовательскихНастроекНаСервере»

Это основной и наиболее правильный метод для отслеживания изменений в отборах и поиске. Проанализируем его преимущества: данное событие вызывается на сервере при любом изменении настроек компоновщика (отборы, сортировка, группировка, поиск), и оно обладает контекстом формы. Это значит, что мы можем напрямую обновлять реквизиты формы (например, наш счетчик) без лишних ухищрений.

Разберем пример реализации:


&НаСервере
Процедура СписокПриОбновленииПользовательскихНастроекНаСервере(Элемент, Настройки)
    // Метод для пересчета количества
    ОбновитьСчетчикСтрокНаСервере();
КонецПроцедуры

Внутри процедуры ОбновитьСчетчикСтрокНаСервере() мы будем выполнять программный запрос к базе данных, учитывая все текущие настройки динамического списка. О том, как написать такой запрос, мы поговорим в разделе про СКД.

Способ 3. Использование события «ПриПолученииДанныхНаСервере» и временного хранилища

Иногда стандартное обновление настроек не срабатывает (например, при специфическом поиске по строке). Тогда на помощь приходит событие самого динамического списка ПриПолученииДанныхНаСервере. Однако здесь есть сложность: процедура является &НаСервереБезКонтекста, и мы не можем напрямую изменить значение реквизита на форме.

Рассмотрим «хитрый» алгоритм с использованием временного хранилища и обработчика ожидания:

  1. В событии ПриСозданииНаСервере создаем уникальный адрес в хранилище и помещаем его в дополнительные свойства настроек списка.
  2. В событии ПриПолученииДанныхНаСервере записываем в этот адрес сигнал (флаг) о том, что данные обновились.
  3. На клиенте запускаем обработчик ожидания, который проверяет этот флаг и, если он установлен, вызывает серверный метод для пересчета количества.

Пример программного кода для реализации этого механизма:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Резервируем адрес во временном хранилище
    АдресВХранилище = ПоместитьВоВременноеХранилище(Ложь, УникальныйИдентификатор);
    // Передаем адрес в настройки списка, чтобы он был доступен в безконтекстном методе
    Список.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("АдресДляФлага", АдресВХранилище);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    // Проверяем наличие адреса и выставляем флаг обновления
    Если Настройки.ДополнительныеСвойства.Свойство("АдресДляФлага") Тогда
        ПоместитьВоВременноеХранилище(Истина, Настройки.ДополнительныеСвойства.АдресДляФлага);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем проверку флага раз в 1-2 секунды
    ПодключитьОбработчикОжидания("ПроверитьОбновлениеСписка", 1, Ложь);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОбновлениеСписка() Экспорт
    Адрес = Список.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.АдресДляФлага;
    Если ПолучитьИзВременногоХранилища(Адрес) = Истина Тогда
        // Сбрасываем флаг и пересчитываем количество
        ПоместитьВоВременноеХранилище(Ложь, Адрес);
        ОбновитьКоличествоНаСервере();
    КонецЕсли;
КонецПроцедуры

Способ 4. Точный программный подсчет количества строк через СКД

Теперь выясним, как именно получить число строк, учитывая все «хитрые» отборы пользователя. Самый надежный способ — использовать КомпоновщикНастроек динамического списка и механизм компоновки данных. Мы заставим систему сформировать текст запроса на основе текущих настроек, но вместо выбора всех полей попросим только КОЛИЧЕСТВО(*). Для лучшего понимания программной настройки схем компоновки пригодятся простые примеры работы с СКД.

Рассмотрим по шагам, как реализовать универсальную функцию подсчета:


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

Важное примечание: Использование метода ПолучитьИсполняемыеНастройки() крайне важно, так как именно он объединяет фиксированные отборы программиста, пользовательские настройки и данные из строки быстрого поиска (Ctrl+F). Если использовать просто Список.КомпоновщикНастроек.Настройки, данные поиска могут быть не учтены.

Рекомендации и оптимизация

Проанализировав все способы, можно сделать следующие выводы для оптимизации работы приложения:

Выяснив причину того, почему стандартные методы иногда не видят изменения в поиске, и внедрив один из предложенных механизмов, вы сможете обеспечить пользователю актуальную информацию о количестве записей в любой момент работы с формой.

← На главную